home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 June: Reference Library / Dev.CD Jun 94.toast / Technical Documentation / Mac Tech Notes (DocViewer) / QuickDraw / TN-QuickDraw / TN-QuickDraw
Encoding:
Text File  |  1994-04-27  |  1.6 MB  |  5,908 lines  |  [ONLN/HLX2]

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. QD 1 - 32-Bit QuickDraw:  Version 1.2 Features
  2. QuickDraw    
  3. Written by:    Guillermo Ortiz    April 1990
  4. This Technical Note describes the changes and enhancements to 32-Bit QuickDraw from version 1.0 (as shipped on the original Color Disk) to version 1.2, which ships with System Software 6.0.5 and later.  This Note assumes familiarity with Inside Macintosh, Volume V, Color QuickDraw, and 32-Bit QuickDraw release notes.
  5. 32-Bit QuickDraw
  6. Version 1.0 of 32-Bit QuickDraw shipped in May 1989 in response to the growing need for Color QuickDraw support for direct color devices and pictures (PICT2) and video boards for large-screen monitors which require 32-bit addressing for black and white operation.  This original version of 32-Bit QuickDraw was a separate file that had to be copied manually into the System Folder.  With the introduction of the Macintosh IIci, Apple put 32-Bit QuickDraw into ROM.  Now System Software 6.0.5 and later offer 32-Bit QuickDraw as an integral part of the System Software which can be installed by the standard Installer (although the file is still separate).
  7. This Note describes the changes and enhancements in version 1.2 of 32-Bit QuickDraw from version 1.0.  Beginning with version 1.2, QuickDraw functionality is identical on all Color QuickDraw machines, including all the performance improvements which were originally only available in the IIci ROM.
  8. New Features (In No Particular Order)
  9. PICTs Contain Font Name Information
  10. Every time you draw text inside of an _OpenPicture and _ClosePicture pair, QuickDraw stores the name of the current font and uses it when playing back the picture.  The opcode used to save this information is $002C and its data is as follows:
  11.     PictFontInfo = Record
  12.                      length   : Integer;    { length of data in bytes }
  13.                      fontID   : Integer;    { ID in the source system }
  14.                      fontName : Str255;
  15.                    END;
  16. QuickDraw only saves this information one time for each font used in a picture.  When QuickDraw plays back a picture, it uses the fontID as a reference into the list of font names which are used to set the correct font on the target system.
  17. For example, the following code:
  18.     GetFNum('Venice', theFontID);    { Set a font before opening PICT}
  19.     TextFont(theFontID);
  20.     pHand2 := OpenPicture (pictRect);
  21.         MoveTo(20,20);
  22.         DrawString(' Better be Venice');
  23.         GetFNum('Geneva', theFontID);
  24.         TextFont(theFontID);
  25.         MoveTo(20,40);
  26.         DrawString('Geneva');
  27.         GetFNum('New York', theFontID);
  28.         TextFont(theFontID);
  29.         MoveTo(20,60);
  30.         DrawString('New York');
  31.         GetFNum('Geneva', theFontID);
  32.         TextFont(theFontID);
  33.         MoveTo(20,80);
  34.         DrawString('Geneva');
  35.     ClosePicture; 
  36. generates a picture containing font information like this:
  37.     OpCode 0x002C {9, 
  38.         "0005 0656 656E 6963 65"}              /* save current font     */
  39.     TxFont 'venice'
  40.     DHDVText {20, 20, " Better be Venice"}
  41.     OpCode 0x002C {9,                          /* save next font name   */
  42.         "0003 0647 656E 6576 61"}
  43.     TxFont 'geneva'
  44.     DVText {20, "Geneva"}
  45.     OpCode 0x002C {11,                         /* ditto                 */
  46.         "0002 084E 6577 2059 6F72 6B"}
  47.     TxFont 'newYork'
  48.     DVText {20, "New York"}
  49.     TxFont 'geneva'                            /* second Geneva does not
  50.                                                  need another $002C guy */
  51.     DVText {20, "Geneva"}
  52. This feature works regardless of the type of picture being saved, including old style PICTs in a black and white port.  Using _OpenCPicture instead of _OpenPicture to start a recording session results in the same functionality.
  53. Direct PixPat Structures Now Supported
  54. QuickDraw now supports 16-bit and 32-bit per pixel PixPat structures (patType = 1).  In addition, it now supports a new patType (3) which uses dithering whenever 16-bit or 32-bit  pixel patterns are displayed on indexed devices.
  55. Direct 'cicn' Resources Now Supported
  56. QuickDraw now supports 16-bit and 32-bit per pixel 'cicn' resources.  The 16-bit per pixel is particularly cool since you save the space required for an 8-bit 'clut'.
  57. GWorlds Can Now Be Allocated in MultiFinder Temporary Memory
  58. You can now use the new useMFTempBit (bit 2) in a call to NewGWorld as an option to allocate pixels in MultiFinder temporary memory.  In addition, you can now allocate screen buffers in MultiFinder temporary memory using the following routine, defined in Pascal and C:
  59. FUNCTION NewTempScreenBuffer (globalRect: Rect; purgeable: BOOLEAN;
  60.                               VAR gdh: GDHandle;
  61.                                VAR offscreenPixMap: PixMapHandle): QDErr;
  62.              INLINE $203C,$000E, $0015,$AB1D; { Move.L #$000E0015,D0
  63.                                                _QDOffscreen
  64.                                              }
  65. pascal QDErr NewTempScreenBuffer (Rect *globalRect, BOOLEAN purgeable,
  66.                               GDHandle *gdh,
  67.                               PixMapHandle *offscreenPixMap)
  68.              ={0x203C,0x000E,0x0015,0xAB1D}; 
  69. Indexed to Indexed Dithering
  70. _CopyBits now supports the ditherCopy transfer mode whenever the destination device is between one and eight bits per pixel, regardless of the depth of the source image.  With this support, an eight-bit image can now be approximated on a one-bit or a four-bit device by using error diffusion.  Furthermore, an eight-bit image could also be dithered to a different set of 256 colors or a four-bit image could be dithered to an eight-bit device that does not have the desired colors.
  71. 32-Bit Addressed PixMap Structures
  72. Version 1.2 defines a new pmVersion (baseAddr32 = 4) for 32-bit pointer baseAddr values.  The baseAddr of such PixMap structures is treated as a 32-bit address, so no stripping or address translation is performed on it in 32-bit mode.  This is a specially useful feature when the base address of a PixMap points to a NuBus™ address, for example in a video grabber board.
  73. A new call, Pixmap32Bit, is now available to inquire if a given PixMap requires 32-bit addressing.
  74. FUNCTION Pixmap32Bit(pmh:pixMapHandle):Boolean;
  75.     INLINE $203C,$0004, $0016,$AB1D; { Move.L #$00040016,D0
  76.                                       _QDOffscreen
  77.                                     }
  78. pascal BOOLEAN Pixmap32Bit(pixMapHandle pmh)
  79.     = {0x203C,0x0004, 0x0016,0xAB1D}; 
  80. Updated GetPixBaseAddress
  81. Version 1.2 updates GetPixBaseAddress to return the address of any PixMap.  The routine does the right address translation or stripping for all PixMap structures, including screen devices, unlocked GWorlds, and 32-bit addressed PixMap structures.  The address it returns is only valid in 32-bit addressing mode. Also unless the PixMap is locked and made unpurgeable, the address returned by GetPixBaseAddress is only valid until any call to QuickDraw or the toolbox is made.
  82. _CopyBits from Screen Devices
  83. The picture recording mechanism has changed so that if you call _CopyBits while recording a picture with the source PixMap being a screen device, the data is correctly accumulated into the picture.  Note that if the screen being copied is not the main screen, then the PixMap must be a 32-bit addressed PixMap.  No auxiliary screen buffer is allocated if the source rectangle covers only one screen.
  84. New Picture Recording Trap
  85. Version 1.2 adds a new call, _OpenCPicture, to create pictures that contain information regarding the native resolution of the recorded image.  When QuickDraw draws this picture, it scales the image to the resolution of the target device.  Applications that need to scale the images directly can also access this information.
  86. FUNCTION OpenCPicture(VAR CPictInfo:CPictRecord):PicHandle;
  87.     INLINE $AA20;
  88. pascal PicHandle OpenCPicture(CPictRecord *CPictInfo)
  89.     =  0xAA20;
  90. where
  91. struct CPictRecord {
  92.       Rect CPicFrame;           /* Bounding rect of Picture at native resolution */
  93.       Fixed CPicHRes;           /* native horizontal resolution in pixels/inch   */
  94.       Fixed CPicVRes;           /* native vertical resolution in pixels/inch     */
  95.       short CPicVersion;        /* version of this PICT info set to -2           */
  96.       short reserved;           /* for future expansion set to zero              */
  97.       long reserved;            /* for future expansion set to zero              */
  98.         };
  99. The new picture header data looks like the following:
  100. Size in bytes    Name    Description
  101.     2    picSize    low word of picture size
  102.     8    picFrame    bounding box at 72 dpi
  103. Picture Header
  104. 2    version op    version opcode = $0011
  105. 2    version    version number = $02FF
  106. 2    Header op    header opcode  = $0C00
  107. 2    version    -2 for PICTs created with _OpenCPicture
  108. 2    reserved
  109. 4    HRes    native horizontal resolution (Fixed)
  110. 4    VRes    native vertical resolution (Fixed)
  111. 8    SrcRect    native source rectangle
  112. 4    reserved
  113. The following is a sample PICT created with _OpenCPicture:
  114.     00 48                          /* low word of size              */
  115.     00 00 00 00 00 7D 00 7D        /* picFrame at 72 dpi            */
  116.     00 11                          /* PICT version opcode           */
  117.     02 FF                          /* version number                */
  118.     0C 00                          /* PICT header Opcode            */
  119.     FF FE                          /* PICT version -2               */
  120.     00 00                          /* reserved                      */
  121.     01 20 00 00                    /* HRes (Fixed)                  */
  122.     01 20 00 00                    /* VRes (Fixed)                  */
  123.     00 00 00 00 01 F4 01 F4        /* picFrame at native resolution */
  124.     00 00 00 00                    /* reserved                      */
  125.     /* picture data follows                                         */
  126.     00 FF                          /* end of picture opcode         */
  127. Random Notes
  128. For information on bug fixes in the System Software 6.0.5 release of 32-Bit QuickDraw (version 1.2), please refer to the System Software 6.0.5 Change History, which is available on the Developer CD Series, AppleLink in the Developer Services Bulletin Board (Developer Services: Macintosh Developer Technical Support: System Software), and the Apple FTP site on the Internet in the ~ftp/pub/dts/sw.license.
  129. Note that the dispatching mechanism for the new _QDOffscreen calls is slightly different than previously documented; it now requires that the high word passed in D0 contain the total length of the parameters (in bytes).  The reason for this change is that if the call is made in an earlier version of 32-Bit QuickDraw, the system can strip the parameters from the stack and return QDError set to the caller (instead of crashing).
  130. Further Reference:
  131. •    Inside Macintosh, Volume V, Color QuickDraw
  132. •    32-Bit QuickDraw Release Notes (available from APDA)
  133. •    System Software 6.0.5 Change History
  134. •    d e v e l o p, Issue I
  135. NuBus is a trademark of Texas Instruments.
  136. QD 2 - BitMapToRegion : So Many Bitmaps, So Little Time
  137. QuickDraw    
  138. Revised by:    Rich Collyer    December 1989
  139. Written by:    Rick Blair    April 1988
  140. This Technical Note discusses the routine BitMapToRegion, which converts a bitmap to a region, and is available in the 32-Bit QuickDraw INIT and from Apple Software Licensing.
  141. Changes since October 1989:  Added trap definitions for developers using the 32-Bit QuickDraw version of this routine without the correct MPW include file.
  142. The following routine is now available to convert a bitmap to a region:
  143. FUNCTION BitMapToRegion(region:RgnHandle; bMap:BitMap): OSErr;
  144. in C:
  145. pascal OSErr BitMapToRegion(RgnHandle region, BitMap bMap);
  146. If you are using the 32-Bit QuickDraw version of this routine without the correct MPW include file, then you need to include one of the following definitions:
  147. Pascal
  148. FUNCTION BitMapToRegion (region: RgnHandle; bMap: BitMap): OSErr;
  149.          INLINE $A8D7;
  150. C
  151. pascal OSErr BitMapToRegion (RgnHandle region, const BitMap *bMap)
  152.              = 0xA8D7;
  153. Assembly
  154. _BitMapToRegion        OPWORD        $A8D7
  155. The region will be built so that all one bits in bMap are inside the region and all zero bits are outside of it.
  156. As with all QuickDraw calls which change a region, BitMapToRegion requires you to pass an existing region (originally created by _NewRgn).  If the region cannot be built due to an insufficient heap space or a size greater than 32K, then the routine will return an appropriate error code and the region will be empty.  If the region would have exceeded 32K, the error will be rgnTooBigErr (-500).
  157. This function is useful for a number of situations where you have (or can produce) a bitmap representing an area.  You can use _CalcMask to produce such a bitmap.  Once you have a region, you can perform region operations (i.e., _PtInRgn, _UnionRgn, or _InsetRgn) or call _DragGrayRgn, for example.
  158. This call is part of the 32-Bit QuickDraw INIT ($A8D7).  If you do not wish to depend on 32-Bit QuickDraw, then you can obtain a version of BitMapToRegion in MPW object format which can be linked into an MPW program, by contacting Apple Software Licensing:
  159.             Apple Software Licensing
  160.             Apple Computer, Inc.,
  161.             20525 Mariani Avenue, M/S 38-I
  162.             Cupertino, CA, 95014
  163.             (408) 974-4667
  164.             AppleLink:  SW.LICENSE
  165. If you licensed the older version of this routine, BitMapRgn, contact Software Licensing about receiving an updated version.  We recommend you update your application to use the new version as soon as possible.
  166. The new version is now named BitMapToRegion to be consistent with the version in 32-Bit QuickDraw and the MPW interfaces.  In addition, BitMapToRegion offers new features.  You can now pass a one-bit pixelmap which has been coerced to a bitmap.  If you pass a pixelmap which is too large, then you will get a pixmapTooDeepErr (-148) error.  You can also pass the portBits of a window, much like you would do with a call to _CopyBits.
  167. There is a potential problem with this routine, since MPW 3.1 include files contain information about 32-Bit QuickDraw.  If you want BitMapToRegion to be available on all machines, then you must use the object file from Software Licensing.  The problem is that when you compile your application with MPW 3.1 or later, the 32-Bit QuickDraw version gets preference over the object file.  You must comment out the routine in the include files if you want to use the object file.  If you only care about using BitMapToRegion on machines running 32-Bit QuickDraw, then you need not do anything.
  168. QD 3 - Color Cursor Cursing : A Leading Cause
  169. QuickDraw    
  170. Revised by:    Alan Mimms    October 1989
  171. Written by:    Alan Mimms    June 1989
  172. Working with color cursors you create from scratch can cause headaches.  This Technical Note may help a bit.
  173. Changes since June 1989:  Added a warning about purgeable 'clut' resources.
  174. If you’re building an application that creates color cursors, you may encounter some quirks present in Color QuickDraw that manifest themselves in hard-to-understand ways.
  175. If your cursor is, say, 15 pixels tall and 9 pixels wide, you might be tempted to use these values for the bounds.bottom and bounds.right, respectively, in your cursor’s pixel map.  Don’t.  The problem is that when the cursor’s image needs to be expanded (i.e., when you specify a two bit-per-pixel cursor and the mouse pointer is on an eight-bit screen) the _SetCCursor trap rounds the width of the pixel map in such a way that you’ll get only the space required for a 15 by 8 pixel map allocated for the expanded cursor data.  When the cursor’s image is expanded into this too-small expanded cursor data handle as a 15 by 9 pixel map, something in your heap will get munched.
  176. The cure is simple. Make certain that you always specify that the pixmapHandle^^.bounds be 16 by 16.  This will cause _SetCCursor to properly allocate the expanded data area, and all will be well in the land.  Since the amount of data drawn for a cursor is specified by the cursor’s pixel values and 'clut' resource, trying to save a few bytes by making the bounds rectangle smaller than 16 by 16 wouldn’t have been very helpful anyway.
  177. Another potential problem is with the color cursor’s color table.  If you load the color table from a 'clut' resource using _GetCTable, you should make sure that the 'clut' is marked non-purgeable while the color cursor is in use.  If you do not take this precaution, bombs will occur if your 'clut' gets purged at in inopportune time.
  178. QD 4 - Colorizing With CopyBits
  179. QuickDraw    
  180. Revised by        March 1988
  181. Written by:    Chris Derossi    November 1987
  182. Inside Macintosh Volume V states that the foreground and background colors are applied to an image during a CopyBits or CopyMask call. Accidental use of this feature can create bizarre coloring effects. This note explains what happens, how to avoid problems, and how to use it.
  183. What Happens
  184. Color QuickDraw has a feature that will allow you to convert a monochrome image to a color image. During a CopyBits or CopyMask call, if the foreground and background colors are not black and white, respectively, Color QuickDraw performs the following operation on every pixel being copied:
  185.     NOTE: color table index = pixel value
  186.     s = color table index of source pixel
  187.     fg = color table index of foreground color
  188.     bg = color table index of background color
  189.     ColoredPixelValue = (NOT(s) AND bg) OR (s AND fg)
  190. If your source image contains only black and white pixels, then all black pixels would become the foreground color and all white pixels would become the background color. This is because the color table index for white is all zeros and the color table index for black is all ones.
  191. For example, suppose your source image was a 4-bit deep color PixMap. Then the color table index for white (in binary) is 0000 and the index for black is 1111. And let’s suppose that your foreground color is green with an index of 1101 while your background color is red with an index of 0011. Then for the black pixels, the above procedure produces:
  192.     ColoredPixelValue = (NOT(1111) AND 0011) OR (1111 AND 1101)
  193.          1101         = (  0000    AND 0011) OR (1111 AND 1101)
  194. And the operation on the white pixels yields:
  195.     ColoredPixelValue = (NOT(0000) AND 0011) OR (0000 AND 1101)
  196.          0011         = (  1111    AND 0011) OR (0000 AND 1101)
  197. Possible Problems
  198. This colorizing will only work on 2-color (i.e. black and white) images, and then only if those colors occupy the first and last entries in the color table. Trying to colorize colors that are not the first and last color table entries will yield unexpected results.
  199. This is mainly due to the fact that the colorizing algorithm uses a pixel’s color table index value rather than its actual RGB color. To illustrate this, let’s assume that foreground and background colors are as above, and your image contains yellow with a color table index of 1000. The colorizing operation would give:
  200.     ColoredPixelValue = (NOT(1000) AND 0011) OR (1000 AND 1101)
  201.          1011         = (  0111    AND 0011) OR (1000 AND 1101)
  202. Since the color table may have any RGB color at the resulting index position, the final color may not even be close to the source, foreground, or background colors.
  203. Similar things occur if you are trying to colorize a black and white image when white and black do not occupy the first and last positions in the color table.
  204. The bottom line rules for CopyBitsing in a color environment are these:
  205. •    Thou shalt set thy background color to white and thy foreground color to black before calling CopyBits or CopyMask, unless thou art coloring a monochrome image.
  206. •    Thou shalt, when colorizing, make sure that the first color table entry is white and the last     color table entry is black.
  207. The second rule is easy to follow because the default color tables are constructed properly, and if you are using the Palette Manager (and you are, right?) then it will make sure that the color tables obey this rule.
  208. How To Colorize—An Example
  209. This code fragment shows how to implement a color fill, like the paint bucket in MacPaint. It relies on three main things: SeedCFill for calculating the fill area, CopyMask for actually changing the bits, and QuickDraw colorizing.
  210. PROCEDURE PaintBucket(where: Point; paintColor: RGBColor);
  211.     VAR
  212.         savedFG    : RGBColor;
  213.         offBits    : BitMap;
  214.     BEGIN
  215.         {First, create an offscreen bitmap.}
  216.         offBits.bounds := myWindow^.portRect;
  217.         WITH offBits.bounds DO BEGIN
  218.             offBits.rowBytes := ((right - left + 15) DIV 16) * 2;
  219.             offBits.baseAddr := NewPtr((bottom-top) * offBits.rowBytes);
  220.         END;
  221.         {Check MemError here! Make sure NewPtr succeeded!}
  222.         SeedCFill(myWindow^.portBits,offBits,myWindow^.portRect,
  223.             myWindow^.portRect,where.h,where.v,NIL,0);
  224.         GetForeColor(savedFG);
  225.         RGBForeColor(paintColor);
  226.         CopyMask(offBits,offBits,myWindow^.portBits,myWindow^.portRect,
  227.             myWindow^.portRect,myWindow^.portRect);
  228.         RGBForeColor(savedFG);
  229.         DisposPtr(offBits.BaseAddr);
  230.     END;
  231. The variable offBits is an offscreen BitMap (not a PixMap) with bounds = myWindow^.portRect.  SeedCFill effectively creates, in the offscreen BitMap,  a monochrome image of the bits that we want to paint. Since offBits contains the exact bits that we want to paint, it is used as both the source image and the mask for CopyMask.
  232. By setting the foreground color to the desired paint color, the result is a colorized version of the mask (the paint area) being copied onto the window’s PixMap without affecting any other bits.
  233. Further Reference:
  234. •    Color QuickDraw
  235. QD 5 - Displaying Large PICT Files
  236. QuickDraw    
  237. Revised by:        March 1988
  238. Written by:    Rick Blair     July 1987
  239. Now that we have scanners and other massive-picture producing types of applications, there is a need to address the problem of how to display a PICT format object that is bigger than a current PICT resource is allowed to be. Note that this technique applies equally well to version 1 and version 2 (word-opcode) pictures as produced by the Macintosh II.
  240. Future Compatibility
  241. Think of the handle returned by a GetResource('PICT',ID) as a “handle” in the more general sense of being an abstract “tag”—something that the ROM routines can use to draw the picture with. Don’t assume that the entire picture has been read into memory or that you can directly read any bytes beyond the basic Picture record structure (picSize followed by picFrame). Someday we may provide a mechanism for the resource to be disk- instead of memory-based. The QuickDraw bottleneck procedures will know how to get data from and put data into the pictures in any case.
  242. Spooling from a PICT file
  243. In order to display pictures of arbitrary size, your application should be able to import a QuickDraw picture from a file of type PICT. This is the file produced by a “Save as…” from MacDraw with the PICT option selected.
  244. What follows is a small program fragment that demonstrates how to spool in a picture from [the data fork of] a PICT file. The picture can be larger than the historical 32K resource size. See technical note #88 if you are unfamiliar with the Signal mechanism. We assume that a CatchSignals has been done before GetandDrawPICTFile is called.
  245. MPW Pascal Example
  246.     {the following variable must be at the top level}
  247.     VAR
  248.        globalRef   : INTEGER;      {refNum of the file to read from}
  249.     {the following procedure must be at the top level}
  250.     PROCEDURE GetPICTData(dataPtr: Ptr; byteCount: INTEGER);
  251.     {replacement for the QuickDraw bottleneck routine}
  252.        VAR
  253.           err         : OSErr;
  254.           longCount   : LONGINT;
  255.        BEGIN
  256.           longCount := byteCount;
  257.           err := FSRead(globalRef,longCount,dataPtr);
  258.           {can't check for an error because we don't know how to handle it}
  259.        END;
  260.     CONST
  261.        abortPICT    = 128;         {error code if DrawPicture aborted}
  262.     PROCEDURE GetDrawPICTFile;     {read in a PICT FILE selected by the user}
  263.        VAR
  264.           wher        : Point;     {where to display dialog}
  265.           reply       : SFReply;   {reply record}
  266.           myFileTypes : SFTypeList; {more Standard FILE goodies}
  267.           numFileTypes: INTEGER;
  268.           savedProcs  : QDProcsPtr;
  269.           myProcs     : QDProcs;   {use CQDProcs for a color window}
  270.           myPicture   : PicHandle; {we need a picture handle for DrawPicture}
  271.           longCount   : LONGINT;
  272.           myEOF       : LONGINT;
  273.           myFilePos   : LONGINT;
  274.        BEGIN
  275.           wher.h := 20;
  276.           wher.v := 20;
  277.           numFileTypes := 1;       {display PICT files}
  278.           myFileTypes[0] := 'PICT';
  279.           SFGetFile(wher,'',NIL,numFileTypes,myFileTypes,NIL,reply);
  280.           IF reply.good THEN BEGIN
  281.              SetStdProcs(myProcs); {use SetStdCProcs for a CGrafPort}
  282.              myProcs.getPicProc := @GetPICTData;
  283.              savedProcs := thePort^.grafProcs; {set the grafProcs to ours}
  284.              thePort^.grafProcs := @myProcs;
  285.              myPicture := PicHandle(NewHandle(SizeOf(myPicture)));
  286.              Signal(FSOpen(reply.fname,reply.vRefNum,globalRef));
  287.              Signal(GetEOF(globalRef,myEOF)); {get EOF for later check}
  288.              Signal(SetFPos(globalRef,fsFromStart,512)); {skip header}
  289.              {read in the (obsolete) size word and the picFrame}
  290.              longCount := SizeOf(myPicture);
  291.              Signal(FSRead(globalRef,longCount,Ptr(myPicture^)));
  292.              DrawPicture(myPicture,myPicture^^.picFrame); {draw the picture}
  293.              Signal(GetFPos(globalRef,filePos)); {get position for check}
  294.              Signal(FSClose(globalRef));
  295.              DisposHandle(Handle(myPicture));
  296.              thePort^.grafProcs := savedProcs; {restore the procs}
  297.              {Check for errors. If there wasn't enough room,}
  298.              {DrawPicture will abort; the FILE position mark}
  299.              {won't be at the end of the FILE.}
  300.              IF filePos <> myEOF THEN Signal(abortPICT);
  301.           END; {IF reply.good}
  302.        END; {GetDrawPICTFile}
  303. MPW C Example
  304. /*replacement for the QuickDraw bottleneck routine*/
  305. pascal void GetPICTData(dataPtr,byteCount)
  306. Ptr            dataPtr; 
  307. short            byteCount;
  308. { /* GetPICTData */
  309.     OSErr            err;
  310.     long            longCount;
  311.     longCount = byteCount;
  312.     err = FSRead(globalRef,&longCount,dataPtr);
  313.     /*can't check for an error because we don't know how to handle it*/
  314. } /* GetPICTData */
  315. /*error code if DrawPicture aborted*/
  316. #define       abortPICT     128         
  317. OSErr GetDrawPICTFile()        /*read in a PICT FILE selected by the user*/
  318. {    /* GetDrawPICTFile */   
  319.     Point         wher;         /*where to display dialog*/
  320.     SFReply    reply;      /*reply record*/
  321.     SFTypeList    myFileTypes;    /*more Standard FILE goodies*/
  322.     short         numFileTypes;
  323.     OSErr        err;
  324.     QDProcsPtr    savedProcs;
  325.     QDProcs    myProcs;    /*use CQDProcs for a color window*/
  326.     PicHandle    myPicture;    /*we need a picture handle for DrawPicture*/
  327.     long        longCount,myEOF,filePos;
  328.           wher.h = 20;
  329.           wher.v = 20;
  330.           numFileTypes = 1;                   /*display PICT files*/
  331.           myFileTypes[0] = 'PICT';
  332.           SFGetFile(wher,'',nil,numFileTypes,myFileTypes,nil,&reply);
  333.           if (reply.good)  
  334.         {
  335.             SetStdProcs(&myProcs);
  336.             /*use SetStdCProcs for a CGrafPort*/
  337.                  myProcs.getPicProc = GetPICTData;
  338.                  savedProcs = (*qd.thePort).grafProcs;
  339.             /*set the grafProcs to ours*/
  340.                  (*qd.thePort).grafProcs = &myProcs;
  341.                  myPicture = (PicHandle)NewHandle(sizeof(Picture));
  342.             err = FSOpen(&reply.fName,reply.vRefNum,&globalRef);
  343.             if (err != noErr) return err;
  344.                   err = GetEOF(globalRef,&myEOF);
  345.             /*get EOF for later check*/
  346.             if (err != noErr) return err;
  347.             err = SetFPos(globalRef,fsFromStart,512);/*skip header*/
  348.                  if (err != noErr) return err;
  349.                  /*read in the (obsolete) size word and the picFrame*/
  350.                  longCount = sizeof(Picture);
  351.                  err = FSRead(globalRef,&longCount,(Ptr)*myPicture);
  352.                  if (err != noErr) return err;
  353.                  DrawPicture(myPicture,&(**myPicture).picFrame); /*draw                                 the picture*/
  354.             err = GetFPos(globalRef,&filePos);/*get position for                                 check*/
  355.                  if (err != noErr) return err;
  356.                  err = FSClose(globalRef);
  357.                  if (err != noErr) return err;
  358.                  DisposHandle((Handle)myPicture);
  359.                  (*qd.thePort).grafProcs = savedProcs;/*restore the                                 procs*/
  360.                  /*Check for errors. if there wasn't enough room,*/
  361.                  /*DrawPicture will abort; the FILE position mark*/
  362.                  /*won't be at the end of the FILE.*/
  363.             if (filePos != myEOF)  return abortPICT;
  364.             else return noErr;
  365.           } /*if (reply.good) */
  366. }     /* GetDrawPICTFile */
  367. More on Picture Compatibility
  368. Many applications already support PICT resources larger than 32K. The 128K ROMs (and later) allow pictures as large as memory (or spooling) will accommodate. This was made possible by having QuickDraw ignore the size word and simply read the picture until the end-of-picture opcode was reached.
  369. For maximum safety and convenience, let QuickDraw generate and interpret your pictures.
  370. While Apple has provided you with the data formats that allow you to read or write picture data directly, we recommend that you always let DrawPicture or OpenPicture and ClosePicture process the opcodes.
  371. One reason to read a picture directly by scanning the opcodes would be to disassemble it to, for example, extract a Color QuickDraw pixel map to save off in a private data structure. This shouldn’t normally be necessary.
  372. If you do look at the picture data be sure and check the version information. You may want to put up an alert in your application that indicates to the user when a picture was created using a later version of the picture format than your application recognizes, letting them know that some elements of the picture cannot be displayed. If the version information indicates a QuickDraw picture version later than the one recognized by your application, your program should skip over the new opcodes and only attempt to parse the ones it knows.
  373. As with reading picture data directly, it is best to use QuickDraw to create data in the PICT format. If you do need to create PICT format data directly, it is essential that you use the latest opcode specifications and that you thoroughly test the data produced on both color and black and white Macintosh machines. Contact Macintosh Developer Technical Support if you are not sure that you have the latest specifications.
  374. Apple does not guarantee that a picture which wasn’t produced by QuickDraw will work.
  375. Further Reference:
  376. •    QuickDraw
  377. •    Technical Note M.IM.PictureOpcodes —
  378.         Internal Picture Format
  379. •    Technical Note M.PT.Signals —
  380.         Signals
  381. QD 6 - Every Picture [Comment] Tells Its Story, Don’t It?
  382. QuickDraw    
  383. Revised by:         March 1988
  384. Written by:    Rick Blair    November 1987
  385. Application-specific picture comment conflict and registration is addressed, along with Developer Technical Support’s method for solving it.
  386. I will assume that the nature and usefulness of picture comments are already well known. The problem I am addressing is that, as it stands, developers must register their comments with us (Developer Technical Support) or run the risk of using the same comments as those used by Apple or within another third party product.
  387. The idea here is to provide a “metacomment” which will contain information about which application owns the comment as well as the comment itself:
  388. ApplicationComment (long comment)    kind = 100  size = n + 6
  389.     data = application signature (i.e. 'MPNT' for MacPaint) = 4 bytes
  390.            application “local” kind = 2 bytes
  391.            comment data = n bytes
  392. In this way each comment may be specific to an application. It is still up to a developer to publish information about the comments they have defined if they wish them to be understood and used by other programs.
  393. Previously assigned and registered comments will still be valid. This means that those  defined for the LaserWriter or MacDraw, for instance, will retain their normal meaning.
  394. Suppose your application (creator = 'MYAP') wanted to define a comment. The appearance of the comment would be as follows (assuming you chose 128 to be the “local” kind for the comment):
  395.     kind = 100; data = 'MYAP' [4 bytes] + 128 [2 bytes] + additional data
  396. Further Reference:
  397. •    QuickDraw
  398. •    Technical Note M.IM.PictComments — 
  399.         Optimizing for the LaserWriter—Picture Comments
  400. QD 7 - Off-Screen Bitmaps
  401. QuickDraw    
  402. Revised by:    Jon Zap & Forrest Tanaka    June 1990
  403. Written by:    Jim Friedlander & Ginger Jernigan    July 1985
  404. This Technical Note provides an example of creating an off-screen bitmap, drawing to it, and then copying from it to the screen.
  405. Changes since April 1990:  Clarified the section on window updates with off-screen bitmaps to explicitly limit these updates to your own windows.
  406. The following is an example of creating and drawing to an off-screen bitmap, then copying from it to an on-screen window.  We supply this example in both MPW Pascal and C.
  407. MPW Pascal
  408. First, let’s look at a general purpose function to create an off-screen bitmap.  This function creates the GrafPort on the heap.  You could also create it on the stack and pass the uninitialized structure to a function similar to this one.
  409. FUNCTION CreateOffscreenBitMap(VAR newOffscreen:GrafPtr; inBounds:Rect) : BOOLEAN;
  410. VAR
  411.   savePort  : GrafPtr;
  412.   newPort   : GrafPtr;
  413. BEGIN
  414.   GetPort(savePort);        {need this to restore thePort after OpenPort changes it}
  415.   newPort := GrafPtr(NewPtr(sizeof(GrafPort)));    {allocate the GrafPort}
  416.   IF MemError <> noErr THEN BEGIN
  417.     CreateOffscreenBitMap := false;                {failed to allocate it}
  418.     EXIT(CreateOffscreenBitMap);
  419.   END;
  420.   {
  421.   the OpenPort call does the following . . . 
  422.     allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide 
  423.     open)
  424.     sets portBits to screenBits
  425.     sets portRect to screenBits.bounds
  426.     etc. (see IM I-163,164)
  427.     side effect: does a SetPort(offScreen)
  428.   }
  429.   OpenPort(newPort);
  430.   {make bitmap exactly the size of the bounds that caller supplied}
  431.   WITH newPort^ DO BEGIN {portRect, clipRgn, and visRgn are in newPort}
  432.     portRect := inBounds;
  433.     RectRgn(clipRgn, inBounds);        {avoid wide-open clipRgn, to be safe}
  434.     RectRgn(visRgn, inBounds);         {in case inBounds is > screen bounds}
  435.   END;
  436.   WITH newPort^.portBits DO BEGIN       {baseAddr, rowBytes and bounds are in
  437.   newPort}
  438.     bounds := inBounds;
  439.     {rowBytes is size of row  It must be rounded up to even number of bytes}
  440.     rowBytes := ((inBounds.right - inBounds.left + 15) DIV 16) * 2;
  441.     {number of bytes in BitMap is rowBytes * number of rows}
  442.     {see note at end of Technical Note about using _NewHandle rather than _NewPtr}
  443.     baseAddr := NewPtr(rowBytes * LONGINT(inBounds.bottom - inBounds.top));
  444.   END;
  445.   IF MemError <> noErr THEN BEGIN    {see if we had enough room for the bits}
  446.     SetPort(savePort);
  447.     ClosePort(newPort);              { dump the visRgn and clipRgn }
  448.     DisposPtr(Ptr(newPort));         { dump the GrafPort}
  449.     CreateOffscreenBitMap := false;
  450.   END
  451.   ELSE BEGIN
  452.     { since the bits are just memory, let's erase them before we start }
  453.     EraseRect(inBounds);            {OpenPort did a SetPort(newPort)}
  454.     newOffscreen := newPort;
  455.     SetPort(savePort);
  456.     CreateOffscreenBitMap := true;
  457.   END;
  458. END;
  459. Here is the procedure to get rid of an off-screen bitmap created by the previous function:
  460. PROCEDURE DestroyOffscreenBitMap(oldOffscreen : GrafPtr);
  461. BEGIN
  462.   ClosePort(oldOffscreen);                       { dump the visRgn and clipRgn }
  463.   DisposPtr(oldOffscreen^.portBits.baseAddr);    { dump the bits }
  464.   DisposPtr(Ptr(oldOffscreen));                  { dump the port }
  465. END;
  466. Now that you know how to create and destroy an off-screen bitmap, let’s go through the motions of using one.  First, let’s define a few things to make the _NewWindow call a little clearer.
  467. CONST
  468.   kIsVisible   = true;
  469.   kNoGoAway    = false;
  470.   kMakeFrontWindow = -1;
  471.   myString     = 'The EYE';  {string to display}
  472. Here’s the body of the test code:
  473. VAR
  474.   offscreen : GrafPtr;    {our off-screen bitmap}
  475.   ovalRect  : Rect;       {used for example drawing}
  476.   myWBounds : Rect;       {for creating window}
  477.   OSRect    : Rect;       {portRect and bounds for off-screen bitmap}
  478.   myWindow  : WindowPtr;
  479. BEGIN
  480.   InitToolbox;                       {exercise left to the reader}
  481.   myWBounds := screenBits.bounds;    { size of main screen }
  482.   InsetRect(myWBounds, 50,50);       { make it fit better }
  483.   myWindow := NewWindow(NIL, myWBounds, 'Test Window', kIsVisible,
  484.                         noGrowDocProc, WindowPtr(kMakeFrontWindow), kNoGoAway, 0);
  485.   IF NOT CreateOffscreenBitMap(offscreen,myWindow^.portRect) THEN BEGIN 
  486.     SysBeep(1);
  487.     ExitToShell;
  488.   END;
  489.   { Example drawing to our off-screen bitmap }
  490.   SetPort(offscreen);
  491.   OSRect := offscreen^.portRect;    { offscreen bitmap's local coordinate rect }
  492.   ovalRect := OSRect;
  493.   FillOval(ovalRect, black);
  494.   InsetRect(ovalRect, 1, 20);
  495.   FillOval(ovalRect, white);
  496.   InsetRect(ovalRect, 40, 1);
  497.   FillOval(ovalRect, black);
  498.   WITH ovalRect DO
  499.     MoveTo((left+right-StringWidth(myString)) DIV 2, (top+bottom-12) DIV 2);
  500.   TextMode(srcXor);
  501.   DrawString(myString);
  502.   { copy from the off-screen bitmap to the on-screen window.  Note that in this
  503.   case the source and destination rects are the same size and both cover the
  504.   entire area.  These rects are allowed to be portions of the source and/or
  505.   destination and do not have to be the same size.  If they are not the same size
  506.   then _CopyBits scales the image accordingly
  507.   }
  508.   SetPort(myWindow);
  509.   CopyBits(offscreen^.portBits, myWindow^.portBits,
  510.            offscreen^.portRect, myWindow^.portRect, srcCopy, NIL);
  511.   DestroyOffscreenBitMap(offscreen);    {remove the evidence}
  512.   WHILE NOT Button DO;                  {give user a chance to see the results}
  513. END.
  514. MPW C
  515. First, let’s look at a general purpose function to create an off-screen bitmap.  This function creates the GrafPort on the heap.  You could also create it on the stack and pass the uninitialized structure to a function similar to this one.
  516. Boolean CreateOffscreenBitMap(GrafPtr *newOffscreen, Rect *inBounds)
  517. {
  518.   GrafPtr savePort;
  519.   GrafPtr newPort;
  520.   GetPort(&savePort);    /* need this to restore thePort after OpenPort */
  521.   newPort = (GrafPtr) NewPtr(sizeof(GrafPort));    /* allocate the grafPort */
  522.   if (MemError() != noErr)
  523.     return false;                 /* failed to allocate the off-screen port */
  524.   /*
  525.   the call to OpenPort does the following . . . 
  526.     allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide
  527.     open)
  528.     sets portBits to screenBits
  529.     sets portRect to screenBits.bounds
  530.     etc. (see IM I-163,164)
  531.     side effect: does a SetPort(&offScreen)
  532.   */
  533.   OpenPort(newPort);
  534.   /* make bitmap the size of the bounds that caller supplied */
  535.   newPort->portRect = *inBounds;
  536.   newPort->portBits.bounds = *inBounds;
  537.   RectRgn(newPort->clipRgn, inBounds);    /* avoid wide-open clipRgn, to be safe  */
  538.   RectRgn(newPort->visRgn, inBounds);     /* in case newBounds is > screen bounds */
  539.   /* rowBytes is size of row, it must be rounded up to an even number of bytes */
  540.   newPort->portBits.rowBytes = ((inBounds->right - inBounds->left + 15) >> 4) << 1;
  541.   /* number of bytes in BitMap is rowBytes * number of rows */
  542.   /* see notes at end of Technical Note about using _NewHandle rather than _NewPtr
  543.      */
  544.   newPort->portBits.baseAddr =
  545.            NewPtr(newPort->portBits.rowBytes * (long) (inBounds->bottom - inBounds-
  546.            >top));
  547.   if (MemError()!=noErr) {   /* check to see if we had enough room for the bits */
  548.     SetPort(savePort);
  549.     ClosePort(newPort);      /* dump the visRgn and clipRgn */
  550.     DisposPtr((Ptr)newPort); /* dump the GrafPort */
  551.     return false;            /* tell caller we failed */
  552.     }
  553.   /* since the bits are just memory, let's clear them before we start */
  554.   EraseRect(inBounds);     /* OpenPort did a SetPort(newPort) so we are ok */
  555.   *newOffscreen = newPort;
  556.   SetPort(savePort);
  557.   return true;               /* tell caller we succeeded! */
  558. }
  559. Here is the function to get rid of an off-screen bitmap created by the previous function:
  560. void DestroyOffscreenBitMap(GrafPtr oldOffscreen)
  561. {
  562.   ClosePort(oldOffscreen);                       /* dump the visRgn and clipRgn */
  563.   DisposPtr(oldOffscreen->portBits.baseAddr);    /* dump the bits */
  564.   DisposPtr((Ptr)oldOffscreen);                  /* dump the port */
  565. }
  566. Now that you know how to create and destroy an off-screen bitmap, let’s go through the motions of using one.  First, let’s define a few things to make the _NewWindow call a little clearer.
  567. #define kIsVisible true
  568. #define kNoGoAway false
  569. #define kNoWindowStorage 0L
  570. #define kFrontWindow ((WindowPtr) -1L)
  571. Here’s the body of the test code:
  572. main()
  573. {
  574.   char* myString = "\pThe EYE";  /* string to display */
  575.   GrafPtr   offscreen;           /* our off-screen bitmap */
  576.   Rect      ovalRect;            /* used for example drawing */
  577.   Rect      myWBounds;           /* for creating window */
  578.   Rect      OSRect;              /* portRect and bounds for off-screen bitmap*/
  579.   WindowPtr myWindow;
  580.   InitToolbox();                 /* exercise for the reader */
  581.   myWBounds = qd.screenBits.bounds;  /* size of main screen */
  582.   InsetRect(&myWBounds, 50,50);  /* make it fit better */
  583.   myWindow = NewWindow(kNoWindowStorage, &myWBounds, "\pTest Window", kIsVisible,
  584.                        noGrowDocProc, kFrontWindow, kNoGoAway, 0);
  585.   if (!CreateOffscreenBitMap(&offscreen, &myWindow->portRect)) {
  586.     SysBeep(1);
  587.     ExitToShell();
  588.     }
  589.   /* Example drawing to our off-screen bitmap*/
  590.   SetPort(offscreen);
  591.   OSRect = offscreen->portRect;  /* offscreen bitmap's local coordinate rect */
  592.   ovalRect = OSRect;
  593.   FillOval(&ovalRect, qd.black);
  594.   InsetRect(&ovalRect, 1, 20);
  595.   FillOval(&ovalRect, qd.white);
  596.   InsetRect(&ovalRect, 40, 1);
  597.   FillOval(&ovalRect, qd.black);
  598.   MoveTo((ovalRect.left + ovalRect.right - StringWidth(myString)) >> 1,
  599.          (ovalRect.top + ovalRect.bottom - 12) >> 1);
  600.   TextMode(srcXor);
  601.   DrawString(myString);
  602.   /* copy from the off-screen bitmap to the on-screen window.  Note that in this
  603.   case the source and destination rects are the same size and both cover the
  604.   entire area.  These rects are allowed to be portions of the source and/or
  605.   destination and do not have to be the same size.  If they are not the same size
  606.   then _CopyBits scales the image accordingly.
  607.   */
  608.   SetPort(myWindow);
  609.   CopyBits(&offscreen->portBits, &(*myWindow).portBits,
  610.            &offscreen->portRect, &(*myWindow).portRect, srcCopy, 0L);
  611.   DestroyOffscreenBitMap(offscreen);    /* dump the off-screen bitmap */
  612.   while (!Button());     /* give user a chance to see our work of art */
  613. }
  614. Comments
  615. In the example code, the bits of the BitMap structure, which are pointed to by the baseAddr field, are allocated by a _NewPtr call.  If your off-screen bitmap is close to the size of the screen, then the amount of memory needed for the bits can be quite large (on the order of 20K for the Macintosh SE or 128K for a large screen).  This is quite a lot of memory to lock down in your heap and it can easily lead to fragmentation if you intend to keep the off-screen bitmap around for any length of time.  One alternative that lessens this problem is to get the bits via _NewHandle so the Memory Manager can move them when necessary.  To implement this approach, you need to keep the handle separate from the GrafPort (for example, in a structure that combines a GrafPort and a Handle).  When you want to use the off-screen bitmap you would then lock the handle and put the dereferenced handle into the baseAddr field.  When you are not using the off-screen bitmap you can then unlock it.
  616. This example does not demonstrate one of the more typical uses of off-screen bitmaps, which is to preserve the contents of windows so that after a temporary window or dialog box obscures part of your windows and is then dismissed, you can quickly handle the resulting update events without recreating all of the intermediate drawing commands.
  617. Make sure you only restore the pixels within the content regions of your own windows in case the temporary window partly obscures windows belonging to other applications or to the desktop.  Another application could change the contents of its windows while they are behind your temporary window, so you cannot simply restore all the pixels that were behind the temporary window because that would restore the old contents of the other application’s windows.  Instead, you could keep keep an off-screen bitmap for each of your windows and then restore them by copying each bit map into the corresponding window’s ports when they get their update events.
  618. An alternate method is to make a single off-screen bitmap that is as large as the temporary window and a region that is the union of the content regions of your windows.  Before you display the temporary window, copy the screen into the off-screen bit map using the region as a mask.  After the temporary window is dismissed, restore the obscured area by copying from the off-screen bit map into a copy of the Window Manager port, and use the region as a mask.  If the region has the proper shape and location, it prevents _CopyBits from drawing outside of the content regions of your windows.  See Technical Note #194, WMgrPortability for details about drawing across windows.
  619. In some cases it can be just as fast and convenient to simply define a picture (PICT) and then draw it into your window when necessary.  There are cases, however, such as text rotation, where it is advantageous to do the drawing off the screen, manipulate the bit image, and then copy the result to the visible window (thus avoiding the dangers inherent in writing directly to the screen).  In addition, this technique reduces flicker, because all of the drawing done off the screen appears on the screen at once.
  620. It is also important to realize that, if you plan on using the pre-Color QuickDraw eight-color model, an off-screen bitmap loses any color information and you do not see your colors on a system that is capable of displaying them.  In this case you should either use a PICT to save the drawing information or check for the presence of Color QuickDraw and, when it is present, use a PixMap instead of a BitMap and the color toolbox calls (Inside Macintosh, Volume V) instead of the standard QuickDraw calls (Inside Macintosh, Volume I).
  621. You may also want to refer to the OffScreen library (DTS Sample Code #15) which provides both high- and low-level off-screen bitmap support for the 128K and later ROMs.  The OffSample application (DTS Sample Code #16) demonstrates the use of this library.
  622. Further Reference:
  623. •    Inside Macintosh, Volumes I & IV, QuickDraw
  624. •    Inside Macintosh, Volume V, Color QuickDraw
  625. •    Technical Note M.IM.PrincipiaOffscreen —
  626.         Principia Off-Screen Graphics Environments
  627. •    Technical Note M.TB.WMgrPort —
  628.          WMgrPortability
  629. •    DTS Macintosh Sample Code #15, OffScreen & #16, OffSample
  630. QD 8 - Old-Style Colors
  631. QuickDraw    
  632. Revised by:    Bill Guschwan    May 1993
  633. Written by:    Rich “I See Colors” Collyer and Byron Han    October 1989
  634. This Technical Note covers limitations of the original Macintosh color model (eight-color) that Inside Macintosh Volume I, page I-173, QuickDraw, does not document.
  635. Changes since October 1989: 
  636. Added definitions of the old-style constants.
  637. Corrected definitions of old-style constants to reflect MPW 3.2 interfaces. 
  638. QuickDraw has always been able to deal with color, just on a very limited basis. Most applications have not made use of this feature, since Color QuickDraw–based Macintosh computers come with a better color model. There are, however, a few nice features that come with the old-style color model. With the old-style colors, it is easy to print color on an ImageWriter with a color ribbon. Another advantage is that developers do not have to write special-case code depending on whether or not a machine has Color QuickDraw.
  639. Now that you are ready to convert to the old-style colors, there are a few things you should know about that do not work with old-style colors. This Note covers the limitations of using old-style colors, as well as the best ways to work around these limitations.
  640. Limitations
  641. The most obvious limitation is that of only eight colors: black, white, red, green, blue, cyan, yellow, and magenta. This limitation is a problem only if you want to produce a color-intensive application; if this describes your application, then you need not read any further in this Note.
  642. The next limitation is that off-screen buffers are not very useful. You can draw into off-screen buffers, but there is no way to get the colors back from the buffer. This leads into the next limitation, which is that _CopyBits cannot copy more than one color at a time.
  643. When you call _CopyBits from an off-screen buffer to your window, you need to set the forecolor to the color you want to copy before calling _CopyBits (for example, to copy a red object, call _ForeColor(redColor)). Now when you copy the object, you can copy only one color. If you copy different colored objects at one time, then you have a problem. The result of a multicolored copy is that all objects copy in the same color, that of the foreground.
  644. It is possible to work with an off-screen buffer and the old-style colors, but it requires a lot of extra work. Unless the objects are really complex, then it is probably easier to just draw the objects directly into your window.
  645. One other limitation does exist. Consider the following code sample. One would assume that this sample would work at all times.
  646.     SetPort (myPort);
  647.     savedFG := myPort^.fgColor;
  648.     ForeColor (redColor);            {or any other color}
  649.     {...drawing takes place here...}
  650.     ForeColor (savedFG);
  651. Surprise. It does not always work. The saved value for the fgColor field of the grafPort is not a classic QuickDraw color if the grafPort is actually a cGrafPort. If dealing with a cGrafPort, the fgColor field actually contains the foreground color’s entry in the color table, so the second call to _ForeColor really messes things up.
  652. The proper way to set and reset the foreground color with classic QuickDraw’s _ForeColor call is as follows:
  653.     SetPort (myPort);
  654.     savedFG := myPort^.fgColor;
  655.     ForeColor (redColor);            {or any other color}
  656.     {...drawing takes place here...}
  657.     myPort^.fgColor := savedFG;      {Manually stuff the old fgColor back.}
  658.     If (32BQD = TRUE) Then           {32BQD is a flag that is made and set by}
  659.         PortChanged (myPort);        {the application; to set it, the application}
  660.                                      {needs to check _Gestalt for 32-Bit QuickDraw.}
  661. This Note also applies to the routine _BackColor.
  662. What Works
  663. The easiest way to work with these limited colors is to use pictures. When you draw the images, you should draw into a picture. Then when you want to draw the images into your window or to a printer, call _DrawPicture. Pictures work well with the old-style colors, and you don’t need to worry about making sure that the forecolor is current when you draw into your window.
  664. Once you have the picture, you can use it to draw into the screen or to the printer port. You can also set the WindowRecords windowPic to equal your PictureHandle so updates are handled by the Window Manager.
  665. What Do Those Constants Mean Anyway
  666. The correct values are 
  667. blackColor     =     33
  668. whiteColor     =     30
  669. redColor    =    205
  670. greenColor    =    341
  671. blueColor    =    409
  672. cyanColor    =    273
  673. magentaColor=    137
  674. yellowColor    =    69
  675. The following discussion is theoretical and was based on the color constants for the MPW 3.1 interfaces. Well, those interfaces were wrong as far as the color constants. The discussion will be kept here to prove once and for all that Macintosh programming sometimes is arbitrary and not logical. On the other hand, the information about the color bits is correct.
  676. Each of the constants contains 9 bits of information, and each bit has a special meaning. Figure 1 illustrates the meaning of each of the bits, while Table 1 shows how each of the color constants fills in the appropriate bits.
  677. Figure 1—Bit Definitions
  678. Table 1  Color-Bit Correlation
  679.     black    white    red    green    blue    cyan    magenta    yellow
  680.     (33)    (30)    (209)    (329)    (389)    (269)    (149)    (89)
  681. Cyan    0    0    0    1    1    1    0    0
  682. Magenta    0    0    1    0    1    0    1    0
  683. Yellow    0    0    1    1    0    0    0    1
  684. Black    1    0    0    0    0    0    0    0
  685. Red    0    1    1    0    0    0    1    1
  686. Green    0    1    0    1    0    1    0    1
  687. Blue    0    1    0    0    1    1    1    0
  688. Inverse    0    1    0    0    0    0    0    0
  689. Normal    1    0    1    1    1    1    1    1
  690. Further Reference:
  691. •    Inside Macintosh, Volume I, page I-173, QuickDraw
  692. •    Technical Note M.IM.Copybits—Of Time and Space and _CopyBits
  693. QD 9 - Palette Manager Changes in System 6.0.2
  694. QuickDraw    
  695. Written by:    Guillermo Ortiz    October 1988
  696. This Technical Note describes the changes and enhancements to the Palette Manager in System Software 6.0.2 and future versions.
  697. Application Palette
  698. Applications now have the ability to define a default palette for the system to use when it needs to define the color environment (i.e., when it creates a color window without an associated palette or displays a dialog box).
  699. The application palette feature is especially cool in cases where a color application uses old-style dialogs and alerts because without an application palette, the system will use the default palette to define the color environment.  Since the system uses the default palette, the color environment may change (will change in 16-color mode) to cause some “cosmic” colors to appear in the active window.  Defining a default application palette with two colors, black and white, solves this problem.
  700. If the system needs a palette to define a color environment, it looks in the resource fork of the application for the 'pltt' ID = 0 resource and uses the palette which it contains.  If the system cannot find this resource in the application’s resource fork, it will use its own default palette (resource 'pltt' ID = 0 in the System file) if present, or, if necessary, it will use the Palette Manager’s built-in palette.
  701. Once an application has set its color environment (by calling _InitMenus, or _InitPalettes in weird instances when there are no menus) it can find the default palette by calling GetPalette ( WindowPtr (-1) ) or change the default palette by calling SetPalette ( WindowPtr (-1), newDefPltt, true ).  Note that the initialization of the Palette Manager with a call to _InitMenus is contrary to the way Inside Macintosh, Volume V, The Palette Manager documents it.
  702. One Palette, Many Ports
  703. You can now associate one palette with many CGrafPort and CWindow records, thus simplifying the use of a single palette with multiple ports and windows; System Software 6.0 and earlier require copies of the palette to use it with different windows.
  704. Although this ability to associate one palette with multiple ports and windows will allow the use of calls like _PmForeColor and _PmBackColor, calling _ActivatePalette with an off-screen port does nothing, and as a result, calling it with an off-screen port will associate the palette with the port but will not cause any change in the color environment.
  705. One important implication of this feature is that DisposeWindow (_DisposWindow) will not dispose of the associated palette automatically since it may be allocated to other ports or windows.  The only exception to this behavior is when an application has used _GetNewCWindow to create the window, there is a 'pltt' resource with the same ID as the window, and the application has not called _GetPalette for the window.
  706. Color Updates
  707. System version 6.0.2 also introduces a new call, _NSetPalette, which complements _SetPalette.  _NSetPalette has the same functionality as _SetPalette, but the CUpdates parameter has been modified from a Boolean to an Integer as follows:
  708. PROCEDURE NSetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;
  709.     nCUpdates: INTEGER);
  710. INLINE $AA95;
  711. _NSetPalette changes the palette associated with dstWindow to srcPalette.  It also records whether the window wants to receive updates as a result of a change to its color environment.  If you want dstWindow to be updated whenever its color environment changes, set nCUpdates to pmAllUpdates.  If you are only interested in updates when dstWindow is the active window, set nCUpdates to pmFgUpdates.  If you are only interested in updates when dstWindow is not the active window, set nCUpdates to pmBkUpdates.
  712. { NSetPalette Update Constants }
  713. pmNoUpdates =     $8000;    {no updates}
  714. pmBkUpdates =     $A000;    {background updates only}
  715. pmFgUpdates =     $C000;    {foreground updates only}
  716. pmAllUpdates =     $E000;    {all updates}
  717. _SetPalette retains its syntax and function:
  718. PROCEDURE SetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;
  719.     CUpdates: Boolean);
  720. INLINE $AA95;
  721. Note:    The trap words for _NSetPalette and _SetPalette are identical.
  722. CopyPalette
  723. PROCEDURE CopyPalette (srcPalette, dstPalette: PaletteHandle;
  724.     srcEntry,dstEntry,dstLength: INTEGER);
  725. INLINE $AAA1;
  726. _CopyPalette is a utility procedure that copies dstLength entries from the source palette into the destination palette; the copy begins at srcEntry and dstEntry, respectively.  _CopyPalette will resize the destination palette when the number of entries after the copy is greater than the original.
  727. _CopyPalette does not call _ActivatePalette, so the application is free to do a number of palette changes without causing a series of intermediate changes to the color environment; the application should call _ActivatePalette after completing all palette changes.
  728. If either of the palette handles are NIL, _CopyPalette does nothing.
  729. QD 10 - Picture Comments—The Real Deal
  730. QuickDraw    
  731. Revised by:    Joseph Maurer    October 1992
  732. Written by:    Ginger Jernigan    November 1986
  733. Changes since March 1988: This Note (formerly titled “Optimizing for the LaserWriter—PicComments”) describes the picture comments defined and interpreted by the Apple printer drivers. Most of the picture comments are specific to PostScript, but we renamed the Note to emphasize that LaserWriter printers are not necessarily PostScript devices, and that QuickDraw printer drivers may implement their own picture comment handling. This Note has been completely rewritten and incorporates all additional insights gained during the last few years. We are also much more determined now to discourage the use of obsolete and problem-laden (although still supported) picture comments, and we carefully point out known problems or limitations of each comment.
  734. Introduction
  735. The QDProcs record (see Inside Macintosh Volume I, page 197) reflects the foundations of the architecture of QuickDraw. The commentProc field points to a procedure that processes picture comments, as included in a picture by means of the PicComment procedure (Inside Macintosh Volume I, page 189). This allows applications to include application-specific additional information in the pictures they create.
  736. The QDProcs record also is the key to understanding how Macintosh printer drivers work. When the application calls PrOpenPage and draws into the printing grafPort, the printer driver collects the drawing commands by hooking into the QDProcs of the printing port. In particular, if an application calls the PicComment procedure while drawing into the printing grafPort, the printer driver gets a chance to capture and process the information contained in the kind and dataHandle parameters.
  737. During the development of the original LaserWriter driver, it became obvious that applications should be able to take advantage of certain PostScript features that were not accessible through standard QuickDraw calls, such as rotated text and graphics, dashed lines, fractional line widths, and smoothed polygons. Also, certain applications needed a way to transmit their own native PostScript instructions to the printer. Picture comments seemed to be the ideal vehicle for providing these capabilities.
  738. Unfortunately, there are conflicts with the device-independent nature of the Macintosh Printing Manager architecture. In this Note, we still want to document picture comments as completely and correctly as possible; and we want to tell you how to use the best of their features, while maintaining the important goal of device-independent printing and all- purpose PICTs. (This is why it has such a painful history!)
  739. First, we give an overview of the picture comments as currently implemented by Apple’s printer drivers. This leads us immediately to the problem section “Cohabitation of QuickDraw and PostScript,” which also shows how to keep the QuickDraw and PostScript graphics states synchronized during printing. Finally, we discuss all the picture comments by subject, in the order suggested by Table 1.
  740. Picture Comments Repertoire
  741. The following picture comments are recognized by all PostScript LaserWriter drivers version 3.1 and later. 
  742. Table 1  PostScript LaserWriter Picture Comments
  743.             Data         
  744.     Type    Kind    Size    Data    Description
  745.     TextBegin    150    6    TTxtPicRec    Begin text function
  746.     TextEnd    151    0    NIL    End text function
  747.     StringBegin    152    0    NIL    Begin string delimitation
  748.     StringEnd    153    0    NIL    End string delimitation    TextCenter    154    8    TTxtCenter    Offset to center of rotation
  749.     LineLayoutOff    155    0    NIL    Turn LaserWriter line layout off
  750.     LineLayoutOn    156    0    NIL    Turn LaserWriter line layout on
  751. #    ClientLineLayout    157    16    TClientLL    Customize line layout error 
  752.                     distribution
  753.     PolyBegin    160    0    NIL    Begin special polygon
  754.     PolyEnd    161    0    NIL    End special polygon
  755.     PolyIgnore    163    0    NIL    Ignore following polygon data
  756.     PolySmooth    164    1    PolyVerb    Close, Fill, Frame
  757.     PolyClose    165    0    NIL    Close the polygon
  758.     DashedLine    180    -    TDashedLine    Draw following lines as dashed
  759.     DashedStop    181    0    NIL    End dashed lines
  760.     SetLineWidth    182    4    Point    Set fractional line widths
  761.     PostScriptBegin     190    0    NIL    Set driver state to PostScript
  762.     PostScriptEnd     191    0     NIL    Restore QuickDraw state
  763.     PostScriptHandle    192    -    PSData     PostScript data in handle
  764. †    PostScriptFile    193    -    FileName    FileName in data handle
  765. †    TextIsPostScript    194    0    NIL    QuickDraw text is sent as PostScript
  766. †    ResourcePS    195    8    Type/ID/Index    PostScript data in a resource file
  767.     PSBeginNoSave    196    0    NIL    Set driver state to PostScript
  768. #    SetGrayLevel    197    4    Fixed    Call PostScript’s setgray operator
  769.     RotateBegin    200    4    TRotation    Begin rotated port
  770.     RotateEnd    201    0    NIL    End rotation
  771.     RotateCenter    202    8    Center    Offset to center of rotation
  772. #    FormsPrinting    210    0    NIL    Don’t clear print buffer after each page
  773. #    EndFormsPrinting    211    0    NIL    End forms printing after PrClosePage
  774. ______________________________________
  775. †    These comments are obsolete.
  776. #    These comments are not recommended.
  777. Most of the comments in Table 1 were designed specifically for the original LaserWriter driver. In fact, the term LaserWriter has been (and often still is) used in the sense of “PostScript printer,” and the LaserWriter driver is known to be basically a QuickDraw-to-PostScript translator. Meanwhile, however, QuickDraw-based LaserWriter models came out, so we should start being more careful in our terminology. This is why we insist on talking about PostScript drivers or PostScript printers when a picture comment applies to PostScript.
  778. QuickDraw printer drivers may implement their own picture comments, or some of the above comments, in order to provide additional capabilities. Certain third-party printer drivers implement text rotation, for example, by supporting the TextBegin/TextCenter/ TextEnd picture comments.
  779. Apple’s QuickDraw printer driver for the LaserWriter SC supports the following three picture comments:
  780.     LineLayoutOff    155    0    NIL    Turn LaserWriter line layout off
  781.     LineLayoutOn    156    0    NIL    Turn LaserWriter line layout on
  782.     SetLineWidth    182    4    Point    Set fractional line widths.
  783. The ImageWriter LQ driver and the first versions of the StyleWriter driver (prior to 7.2) implement the LineLayoutOff and LineLayoutOn picture comments. Even the ImageWriter driver reacts to picture comments:
  784.     BitMapThinningOff    1000    0    NIL    Turn off hi-res bitmap thinning
  785.     BitMapThinningOn    1001    0    NIL    Turn on hi-res bitmap thinning
  786. The ImageWriter driver does the same toggling of the “bitmap thinning” of fat bitmaps in Best mode, when it encounters a TextBegin or TextEnd comment (undocumented feature—never mind!). The ImageWriter LQ driver handles these comments similarly.
  787. The current StyleWriter driver (version 7.2.2) and the personal LaserWriter LS driver do not support any picture comments at all. 
  788. The point of all this is:
  789. It is impossible to determine which picture comments
  790. are supported by which printer driver.
  791. In other words, your application should never assume a particular picture comment is available, but your application also should not defeat the device-independent design of the Macintosh printing architecture by writing printer driver–specific code! 
  792. Of course, you know (Inside Macintosh Volume II, page 152) that the high byte of the prStl .wDev field of the print record identifies a printer driver species, and that a value of $03 tells you the printer driver belongs to the PostScript LaserWriter driver ancestry. As a matter of fact, many applications use this information to achieve special printing features not available through the Printing Manager interface.
  793. And, of course, you also know that we don’t like this idea. One reason is future system software may allow spool files to be redirected to a printer other than the one chosen when you sent your printing instructions (including picture comments). Another reason is that picture comments usually are included in PICTs; documents containing such pictures should print with optimal results on any printer configuration. And, finally, you never know what the future holds for you, in terms of new printing devices or new printer drivers—or a new printing architecture!
  794. Instead, if a picture (i.e., a sequence of imaging instructions) contains picture comments to enhance the output on devices that support them, it should also contain a standard QuickDraw representation as a fallback solution, in case the rendering device does not recognize the picture comments. The design and implementation of these picture comments should incorporate conventions to make this cohabitation of two representations in one picture possible.
  795. Cohabitation of QuickDraw and PostScript
  796. Device-Independent Pictures
  797. We can think of the Printing Manager’s PrOpenPage and PrClosePage calls as being analogous to the OpenPicture and ClosePicture calls (which, by the way, reminds us to never call OpenPicture between PrOpenPage and PrClosePage; see Inside Macintosh Volume II, page 160). In both cases, a stream of imaging instructions is recorded for deferred rendering. We want to create pictures that include both QuickDraw and optimized PostScript representations so that we obtain the best results in all circumstances. We must take special care for third-party QuickDraw printer drivers that support picture comments originally intended for PostScript devices only.
  798. Let’s start with the easy ones.
  799. The two picture comments PostScriptBegin and PostScriptEnd clearly suggest that any imaging instructions in between are intended exclusively for PostScript printing devices. In the case of the PostScript LaserWriter driver, the effect of PostScriptBegin is to disable all bottlenecks except commentProc, txMeasProc, getPicProc, and putPicProc. This means that QuickDraw’s text, line, shape (Rects, RoundRects, Ovals, Arcs, Polygons) and bitmap drawing calls don’t have any effect in the printing grafPort when enclosed by PostScriptBegin and PostScriptEnd. Instead, the PostScript LaserWriter driver expects to receive the imaging instructions as data enclosed in the PostScriptHandle comment. This way, both the PostScript and QuickDraw representation can coexist in the same picture without conflict. As a consequence, non-PostScript printer drivers, unable to interpret general PostScript text, must not imitate this behavior of ignoring QuickDraw instructions, even when they implement other picture comments such as TextBegin and TextEnd for text rotation. Otherwise, they would miss the QuickDraw representation of some PostScript imaging.
  800. The text rotation picture comments (TextBegin, TextCenter, TextEnd) silently include the assumption that a printer driver that supports these comments
  801. a. ignores the QuickDraw clipping region between TextBegin and TextEnd
  802. b. ignores the QuickDraw CopyBits instruction within TextBegin/TextEnd
  803. This way, a bitmap representation of the rotated text can be included in the picture. It will be used only if the TextBegin/TextEnd comments are not supported. Conversely, the QuickDraw commands required to draw the text to be rotated by the printer driver are “hidden” from QuickDraw by setting the clipping region to empty, which is ignored by the driver supporting the comments.
  804. The polygon picture comments provide another solution to the problem, in form of the special comment PolyIgnore. It allows one to include a QuickDraw representation of the smoothed polygon, ignored by a driver that supports polygon smoothing (such as via PostScript’s curve operator). And for filled polygons, QuickDraw’s region concept works around a conflict of who owns which polygon (see sample code later in this Note).
  805. Some picture comments (such as the line layout comments) do not require a fallback solution in case they are not supported by a printer driver; or the feature, if absent, is not a big loss (such as SetLineWidth, provided you use it only for widths smaller than one 72-dot-per-inch (dpi) QuickDraw pixel). 
  806. But for the picture comments DashedLine/DashedStop and RotateBegin/ RotateCenter/RotateEnd, there is no general solution to the “cohabitation” problem; and we are distressed about it. It is obvious that they have been defined with the PostScript LaserWriter driver in mind, without anticipating a future furnished by some 150 third-party printer drivers. The only way to include both representations in these cases is indeed to assume that only PostScript drivers will support the picture comment, such that the PostScriptBegin and PostScriptEnd comments can be used to “comment out” the QuickDraw representation.
  807. Even under the above assumption, we still need a trick to prevent the QuickDraw calls within the scope of the picture comments from showing up when the comments are not recognized. Fortunately, early Macintosh developers discovered a QuickDraw feature that, unintentionally, solves the problem. Passing the “magic” mode 23 to PenMode inhibits QuickDraw’s normal drawing, but still lets the LaserWriter driver see the drawing instructions come through the bottlenecks, so that it can translate them into PostScript. Note that this pen mode always has been undocumented, and that using it was considered a compatibility risk and frowned upon for some time. Given the current state of affairs, however, there is no reason anymore to be paranoid about it.
  808. Keeping QuickDraw and PostScript Synchronized
  809. There are two situations, in the context of picture comments, where the design of the PostScript LaserWriter driver requires special precautions from the application programmer. 
  810. First, certain QuickDraw instructions like Move, MoveTo, PenPat, and PenSize change the state of the grafPort, without going through the QDProcs bottleneck procedures. A Macin-tosh printer driver takes these changes into account only at the time it executes an actual drawing instruction. Remember, the printer driver hooks into the QDProcs to get execution time and only “sees” instructions coming through the QDProcs. Nothing is wrong with it—unless PostScript code is woven into the graphics instructions by means of picture comments. (Note that PostScript code may be generated transparently when the LaserWriter driver encounters certain picture comments.) If the PostScript code assumes that the current state of the grafPort corresponds to what you expect it to be, then you have to flush the state of the grafPort explicitly before inserting the PostScript code. This is easier than it sounds; just do something inoffensive that goes through the QDProcs.lineProc bottleneck, like in the following utility procedure:
  811. PROCEDURE FlushGrafPortState;
  812. { This routine causes the state of the Printing Manager's grafPort to be }
  813. { flushed out to the LaserWriter, by making a dummy call through the     }
  814. { QDProcs.lineProc bottleneck. Pen size and pen location are preserved.  }
  815.    VAR
  816.       penInfo: PenState;
  817.    BEGIN
  818.       GetPenState(penInfo);                              { Save pen size. }
  819.       PenSize(0,0);                                  { Make it invisible. }
  820.       Line(0,0);                           { Go through QDProcs.lineProc. }
  821.       PenSize(penInfo.pnSize.h, penInfo.pnSize.v);    { Restore pen size. }
  822.    END;
  823. Another unwanted effect is related to the PostScript LaserWriter driver’s multiple internal buffering of generated PostScript code. The PostScript code generated for text drawing instructions (which usually involves font queries and, sometimes, font downloading) is buffered independently from the PostScript code inserted by means of picture comments. In certain cases, this results in apparently nonsequential execution of drawing instructions, and may affect clipping regions or may have side effects on the PostScript code you included in picture comments. In order to synchronize the sequence of QuickDraw instructions with the generation of PostScript code, you need to call the following procedure:
  824. PROCEDURE FlushPostScriptState;
  825. { This routine flushes the buffer maintained by the LaserWriter driver. }
  826. { All PostScript, generated either by the app or by the LaserWriter     }
  827. { driver, will be sent to the device.                                   }
  828.    BEGIN
  829.       PicComment(PostScriptBegin, 0, NIL);
  830.       PicComment(PostScriptEnd, 0, NIL);
  831.    END;
  832. In the following discussion of picture comments, we’ll refer to these two utility routines as appropriate.
  833. Text Rotation
  834. Comments:    TextBegin, TextCenter, TextEnd
  835. These comments give access to PostScript’s capabilities of rotating, flipping, and justifying text. They are intended for applications likely to be used with PostScript printers (such as desktop publishing and advanced drawing applications), but which don’t want to use PostScript explicitly. Note that some non-PostScript printer drivers support these comments as well. For situations where the comments are not supported (such as the QuickDraw screen, or most QuickDraw printer drivers), you must provide a bitmap represen-tation of the rotated text as an alternative. 
  836. Let’s look at sample code right away.
  837. USES  PicComments;  { See Appendix; defines constants for just and flip and   }
  838.                     { the structures referred to by TTxtPicHdl and TCenterHdl.}
  839.    
  840. PROCEDURE QDStringRotation(s: Str255; ctr: Point; 
  841.                            just, flip: Integer; rot: Fixed); EXTERNAL;
  842. { This routine should generate a bitmap of the rotated and flipped text       }
  843. { and use CopyBits to draw it to the grafPort. Left as an exercise ...        }
  844. PROCEDURE DrawXString(s: Str255; ctr: Point; just, flip: Integer; rot: Fixed);
  845. { Draws the string s rotated by rot degrees around the current point, offset  }
  846. { by ctr, justifying and flipping according to the just and flip parameters.  }
  847. { If the printer driver supports the TextBegin, TextCenter, and TextEnd       }
  848. { picture comments, it rotates the text at device resolution; otherwise, the  }
  849. { external procedure QDStringRotation is called to image the rotated string.  }
  850. { The pen position is preserved. }
  851.    VAR
  852.       hT: TTxtPicHdl;     { Defined in PicComments.p - see Appendix. }
  853.       hC: TCenterHdl;     { –"– }
  854.       zeroRect: Rect;
  855.       pt: Point;
  856.       oldClip: RgnHandle;
  857.    BEGIN
  858.       GetPen(pt);  { to preserve the pen position }
  859.       hT := TTxtPicHdl(NewHandle(SizeOf(TTxtPicRec)));
  860.       hC := TCenterHdl(NewHandle(SizeOf(TCenterRec)));
  861.       { No error handling: if these fail, we are in deep trouble anyway ...}
  862.       WITH hT^^ DO BEGIN
  863.          tJus      := just;
  864.          tFlip     := flip; 
  865.          tAngle    := - FixRound(rot); { I like counterclockwise better. }
  866.          tLine     := 0; { reserved }
  867.          tCmnt     := 0; { used internally by the printer driver }
  868.          tAngleFixed := - rot;
  869.       END;
  870.       hC^^.y := Long2Fix(ctr.v);
  871.       hC^^.x := Long2Fix(ctr.h);
  872.       PicComment(TextBegin,SizeOf(TTxtPicRec),Handle(hT));
  873.       PicComment(TextCenter,SizeOf(TCenterRec),Handle(hC));
  874.       { PostScript graphics state now has rotated/flipped coordinates. }
  875.       oldClip := NewRgn;
  876.       GetClip(oldClip);
  877.       SetRect(zeroRect,0,0,0,0);
  878.       ClipRect(zeroRect);  { Hides the following DrawString from QuickDraw }
  879.       DrawString(s); { in the rotated PostScript environment. }
  880.       ClipRect(oldClip^^.rgnBBox);
  881.       { Now the "fallback" bitmap representation; see the comments above  }
  882.       { at the declaration of the QDStringRotation procedure. }
  883.       QDStringRotation(s, ctr, just, flip, rot);
  884.       PicComment(TextEnd,0,NIL); { Set environment back to the original state }
  885.       DisposHandle(Handle(hT));
  886.       DisposHandle(Handle(hC));
  887.       MoveTo(pt.h,pt.v);  { to preserve the pen position }
  888.    END;
  889. The preceding discussion about including both QuickDraw and PostScript representations and the comments included in the source code say it all: The conventions tied to the usage of the TextBegin and TextEnd picture comments allow you to take advantage of a printer driver’s implementation of high-resolution text rotation, while including a bitmapped representation for where the comments are not supported.
  890. Some Additional Hints
  891. •    Because of QuickDraw’s orientation of the vertical coordinate axis, the rotation angle is measured clockwise. Nothing prevents us from using the negative angle if we are used to the counterclockwise orientation.
  892. •    The angle is measured in degrees (0..360), and passed as a Fixed type number (that is, if taken as a LongInt value, you have to divide it by 65536 to obtain the angle in degrees). For integer angles, it is possible to use a reduced TTxtPicRec structure that does not contain the tRotFrac field. The PostScript LaserWriter driver uses GetHandleSize(hT) to determine whether it must use the fractional angle in the tRotFrac field. To be safe, always set the tRot field to FixRound(tRotFrac) if you go with the extended TTxtPicRec (as we do here).
  893. •    It is convenient that clipping regions are ignored between the TextBegin and TextEnd picture comments, because it allows us to clip out the DrawString on printers that don’t support these comments. Unfortunately, this also means that text rotated this way can’t be clipped. If clipping of rotated text is required, you’ll have to do it entirely within PostScript.
  894. •    Due to the LaserWriter driver’s internal buffering of generated PostScript code, the effect of ignoring clip regions may be propagated to preceding sections of your drawing instructions. We recommend calling the FlushPostScriptState procedure described earlier immediately before the TextBegin comment.
  895. •    The tJus field in the TTxtPicRec, if different from tJusNone, tells the printer driver to maintain either the left, right, or center point of the string without recalculating the interword and intercharacter spacing. The tJusFull value specifies that the original length of the string (on the QuickDraw screen) must be maintained. This is important when the printer font has widths different from those of the screen font, and when you rotate justified blocks of text.
  896. •    The tFlip field in the TTxtPicRec specifies horizontal or vertical flipping about the center point specified by the TextCenter comment.
  897. •    The TextCenter comment specifies the center of rotation for any text enclosed within the TextBegin and TextEnd calls, as an offset to the location of the current point. The rotation is achieved by changing PostScript’s coordinate system. A sequence of DrawString – MoveTo instructions is rotated as a whole until TextEnd is encountered.
  898. •    Some versions of double-byte Kanji systems print Kanji characters by calling CopyBits instead of calling standard text drawing routines. This means the comments in the Text Rotation family cannot be used with these fonts. Instead, use the Graphics Rotation comment family described later in this Note.
  899. Line Layout Control
  900. Comments:    LineLayoutOn, LineLayoutOff, ClientLineLayout
  901. When drawing to a printing grafPort, the selected printer driver does a lot of work “behind the scenes” to try to maintain the infamous “What-You-See-Is-What-You-Get” (WYSIWYG) metaphor from the screen to the paper, and generally to make the printed output look as good as possible. Depending on the target device, the printer driver, and the configuration of fonts in the system, the font you draw text with may be scaled, smoothed, remapped, or even replaced by a font built into the printer. In nearly all cases where the device resolution of the printer is different from QuickDraw’s “hard-coded” 72-dpi screen resolution, the width of text rendered on the printer is different from the text width on the screen. This is due to nonproportionally scaling bitmapped fonts, different character widths after font substitution, and rounding errors of fractional character widths on the screen. The difference in the width of a line of text is called the line layout error.
  902. The printer driver is responsible for adjusting the word and character spacing in the printed output so that the two widths are identical. If it doesn’t, apparently fully justified text on the screen may appear ragged on the paper, and certain lines of text may extend beyond the right border and be badly clipped. Many existing applications make this task really difficult for the printer drivers (don’t blame them, though!). They position the words (or even characters) separately on a line, and the printer driver has to figure out how to collect the complete line before applying its line layout algorithm to distribute the difference of the text widths into word and character spacing. Given the uneven distribution of the character width differences, and the requirement of achieving good typographical quality in the printed output, it is unavoidable that the position and width of a word within a justified line differs slightly from what appears on the screen; only the length of the whole line is maintained.
  903. In computing the required line layout adjustments, the LaserWriter driver proceeds as follows:
  904. 1.    It collects text coming through the printing grafPort’s textProc bottleneck, and heuristically puts it together into what it “believes” is a logically contiguous line of text. This includes text moved vertically away from the baseline, to take care of indices or exponents in the text. The process of accumulating text is stopped when the LaserWriter driver detects that the horizontal component of the pen position has changed since the previous text drawing instruction, or when picture comments like TextBegin, TextEnd, StringBegin, StringEnd are encountered.
  905. 2.    It determines the width of the accumulated logical line of text, both on the screen and on the printer, and distributes the line layout error among the interword and intercharacter spacing of the printed output.
  906. The LineLayoutOff picture comment disables only the second step (distribution of the line layout error); the heuristic algorithm of accumulating text into a logically contiguous piece is not affected. Otherwise, if the character widths of the printer font are different from those of the screen font, and if the text contains exponents or indices, the latter would often be misplaced.
  907. The following code fragment shows a probably unexpected consequence of this behavior. We draw a line in two pieces three times. A vertical line shows the starting pen position of the second DrawString call. The second line is enclosed by LineLayoutOff and LineLayoutOn picture comments.
  908. PROCEDURE ObserveLineLayout;
  909.    CONST
  910.       testString1 = 'Whatever you like, preferably ';
  911.       testString2 = 'with spaces, long and short words';
  912.       fontName = 'New York';
  913.       fontSize = 14;
  914.       x0 = 20; { starting point }
  915.       y0 = 40;
  916.       h  = 30; { line height }
  917.    VAR
  918.       familyID: Integer;
  919.       w, y    : Integer;
  920.    BEGIN
  921.       GetFNum(fontName, familyID);
  922.       TextFont(familyID);
  923.       TextSize(fontSize);
  924.  
  925.       w := StringWidth(testString1);
  926.       y := y0;
  927.       MoveTo(x0 + w, y - h);
  928.       Line(0, 4 * h);    { This is to estimate the difference. }
  929.       { Draw the first line, in two pieces. }
  930.       { This is the default line layout behavior of the LaserWriter driver. }
  931.       MoveTo(x0, y);          
  932.       DrawString(testString1);
  933.       MoveTo(x0 + w, y);
  934.       DrawString(testString2);
  935.       { Draw the second line, in the same way as above. }
  936.       { Because of the LineLayoutOff picture comment, the unmodified widths }
  937.       { of the printer font are used. }
  938.       y := y + h;
  939.       PicComment(LineLayoutOff, 0, NIL);
  940.                                    { ••• (1)  •••}
  941.       MoveTo(x0, y);
  942.       DrawString(testString1);
  943.       MoveTo(x0 + w, y);
  944.                                    { ••• (2)  •••}
  945.       DrawString(testString2);
  946.       y := y + h;
  947.       PicComment(LineLayoutOn, 0, NIL);
  948.       { Back to the original behavior. }
  949.       MoveTo(x0, y);
  950.       DrawString(testString1);
  951.       MoveTo(x0 + w, y);
  952.       DrawString(testString2);
  953.    END;
  954. And this is (approximately) the output of the ObserveLineLayout (with LaserWriter driver version 7.1.1, and the default setting “Font Substitution enabled”):
  955. Figure 1—Effect of the LineLayoutOff comment
  956. For most noticeable effects, we choose the bitmapped New York font, such that the LaserWriter driver substitutes PostScript Times (note that there are no line layout problems with TrueType fonts, unless the TrueType font has the same name and different cha-rac-ter widths as a printer-resident PostScript font). The screen font New York is larger than the PostScript font Times, and in the first and third lines, the printer driver (after accumulating testString1 and testString2 into one logical line) distributes the line layout error (mainly) among the spaces between words. You may even notice that the starting point of testString2 (“with ...”) has been slightly moved to the left in the process. The width of the whole line, however, is the same as on the screen.
  957. The second line, where the LineLayoutOff comment is active, demonstrates a dramatic counterexample to the popular belief that this picture comment is here to assure precise positioning of text. It seems the opposite is true, and the LaserWriter driver has deliberately ignored the MoveTo(x0+w,y) instruction! What we would have expected is this:
  958. Figure 2—Desired result of the LineLayoutOff comment
  959. The attentive reader already knows the explanation. As mentioned earlier, we must break the LaserWriter driver’s heuristic line accumulation algorithm before drawing testString2. Short of adequate documentation, developers have found out that a FlushGrafPortState call right after the MoveTo(x0+w,y) instruction has the desired effect (see {••• (2) •••} in the code snippet given earlier). Unfortunately, it creates quite a lot of overhead in the pictures, and penalizes all printer drivers that don’t need it. A better solution is to use the StringBegin and StringEnd picture comments at the markers {••• (1) •••} and {••• (2) •••} in the code shown earlier. This indicates that testString1 is to be considered a logically independent text entity, and must not be put together with any other pieces of text coming through the textProc bottleneck. The overhead of these comments is much smaller, and they don’t affect other printer drivers at all.
  960. The ClientLineLayout picture comment, supported by the (PostScript) LaserWriter driver, has never been documented. Its effect is rather subtle and very specific to the PostScript LaserWriter driver. Basically, it allows the application to redefine the character that absorbs the major part of the line layout error (usually the space character), and the percentages of the “major” and “minor” parts of the line layout error (usually 80 percent versus 20 percent). The “minor” part is distributed across intercharacter spacing. 
  961. Only very ambitious page layout applications might be interested in this functio-na-lity; but then, they should rather aim at a more general scheme of line layout control that does not rely upon this very driver-specific picture comment.
  962. The PicComment.p interface (see the Appendix) describes the TClientLLRecord structure passed through the handle parameter to the picture comment. If you want, feel free to experiment with it; we recommend, however, that you do not use this picture comment in your application. 
  963. Caveats
  964. •    Some older printer drivers supporting the LineLayoutOff picture comment are unable to correctly obey a subsequent LineLayoutOn picture comment.
  965. •    Don’t forget that if you use LineLayoutOff, the burden of “WYSIWYG” is now on your shoulders, and not the printer driver’s.
  966. •    A previous version of this Note said that setting the Font Manager’s FractEnable global to TRUE implied the effect of the LineLayoutOff picture comment. As it turned out, the statement was based on observations with a specific (older) version of the LaserWriter driver, and is not true in general. The setting of FractEnable does have some more or less subtle effects on the line layout algorithm, however; and this is quite plausible. Similarly, the results of combining the picture comments LineLayoutOff and LineLayoutOn with calls to SpaceExtra (Inside Macintosh Volume I, page 172) or CharExtra (Inside Macintosh Volume V, page 77) are sometimes unpredictable, depending on the particular printer driver.
  967. And Finally the Good News
  968. Given that the effect of the LineLayoutOff and LineLayoutOn comments does not require any changes in your printing code, you don’t have to worry whether or not a particular driver supports them. They are useful mainly when you’re sure you want no external assistance in computing word and character spacing for full justification, or when you need precise control over the horizontal placement of words and characters (such as in forms or tabulated text) and understand how to achieve this.
  969. String Delimitation 
  970. Comments:    StringBegin, StringEnd
  971. These comments allow applications to specify the logical beginning and end of a string, possibly drawn with multiple calls to a QuickDraw text drawing routine (such as DrawChar). If this was their only raison d’être, they would have no relationship with the PostScript LaserWriter driver. But, as already let out in the preceding section on line layout, they are important to notify the printer driver that it should consider the text coming through the textProc bottleneck between StringBegin and StringEnd as an independent entity. Otherwise, the driver might continue to perform its heuristic accumulation of text drawing instructions for the same line, and defeat your text positioning intentions. Indeed, both StringBegin and StringEnd trigger the generation of PostScript instructions for drawing the text that has been accumulated in a line layout buffer, and reinitialize the internal variables for line layout computations. In other words, you need these picture comments to turn the LaserWriter driver’s line layout behavior completely off.
  972. Polygon Comment Family
  973. Comments:    PolyBegin, PolyEnd, PolyClose, PolySmooth, PolyIgnore
  974. PostScript has the built-in capability of drawing cubic Bézier curve sections (see the PostScript Language Reference Manual, Second Edition, page 393). This is convenient for “smoothing” of polygons. The polygon-related picture comments have been provided to give applications easy access to this PostScript feature, with provision for including a QuickDraw approximation of the curve.
  975. Schematically, the polygon comments are used as follows:
  976.     PolyBeginComment;        { Put the PostScript driver into “polygon mode.” }
  977.     ClipRect(zeroRect);        { Hide the following from QuickDraw. }
  978.     PolyCloseComment;        { Optionally, if “closed” smoothing desired. }
  979.     PolySmoothComment;    { Tell the driver to draw a Bézier curve. }
  980.     DrawPolygon;        { Invisible for QuickDraw; PostScript output = curve. }
  981.     PolyIgnoreComment;    { The driver will ignore the following line drawing. }
  982.     SetClip(origClipRgn);    { Make it visible for QuickDraw. }
  983.     DrawQDPolygon;        { Usually, a QuickDraw approximation of the curve. }
  984.     PolyEndComment;        { PostScript driver resumes standard mode. }
  985. A piece of sample code is sometimes worth more than one or two pictures; below, you’ll find both. For clarity and completeness of the exposition, we provide the coordinate definition of the polygons through arrays of Points, initialized in a preliminary DefineVertices procedure. You can enclose the PolygonDemo procedure between OpenPicture and ClosePicture calls to create a picture containing both QuickDraw and PostScript representations (see Figures 3 and 4), or you can use it as is when a printing page is open.
  986. USES PicComments;
  987. { See Appendix of this Note for the definition of the TPolyRec structure. }
  988.    CONST
  989.       kN = 4; { number of vertices for PostScript }
  990.       kM = 6; { number of vertices for QuickDraw approximation }
  991.    TYPE
  992.       PointArray = array[0..0] of Point;  { range checking OFF }
  993.       PointArrayPtr = ^PointArray;
  994. PROCEDURE DefineVertices(VAR p,q: PointArrayPtr);
  995.    CONST
  996.       cx = 280;
  997.       cy = 280;
  998.       r0 = 200;
  999.    BEGIN
  1000.    { The array p^ contains the control points for the Bézier curve: }
  1001.       SetPt(p^[0],cx + r0,cy);
  1002.       SetPt(p^[1],cx,cy + r0);
  1003.       SetPt(p^[2],cx - r0,cy);
  1004.       SetPt(p^[3],cx,cy - r0);
  1005.       p^[4] := p^[0];
  1006.    { q^ contains the points for a crude polygon approximation of the curve: }
  1007.       q^[0] := p^[0];
  1008.       SetPt(q^[1],cx,cy + round(0.7 * (p^[1].v - cy)));
  1009.       SetPt(q^[2],(p^[1].h + p^[2].h) DIV 2,(p^[1].v + p^[2].v) DIV 2);
  1010.       SetPt(q^[3],cx + round(0.8 * (p^[2].h - cx)),cy);
  1011.       SetPt(q^[4],q^[2].h,cy + cy - q^[2].v);
  1012.       SetPt(q^[5],q^[1].h,cy + cy - q^[1].v);
  1013.       q^[6] := q^[0];
  1014.    END;
  1015. PROCEDURE PolygonDemo;
  1016.    VAR
  1017.       p,q: PointArrayPtr;
  1018.       aPolyVerbH: TPolyVerbHdl;
  1019.       i: Integer;
  1020.       clipRgn, polyRgn: RgnHandle;
  1021.       zeroRect: Rect;
  1022.    BEGIN
  1023.       p := PointArrayPtr(NewPtr(SizeOf(Point) * (kN + 1)));
  1024.       q := PointArrayPtr(NewPtr(SizeOf(Point) * (kM + 1)));
  1025.       IF (p = NIL) OR (q = NIL) THEN DebugStr('NewPtr failed');
  1026.       DefineVertices(p,q);
  1027.       PenNormal;              { First show the standard QuickDraw polygon. }
  1028.       MoveTo(p^[0].h,p^[0].v);
  1029.       FOR i := 1 TO kN DO LineTo(p^[i].h,p^[i].v);
  1030.    
  1031.       PenSize(2,2);                { Now show the same polygon "smoothed." }
  1032.       PenPat(gray);
  1033.       { First, the PostScript representation, clipped off from QuickDraw: }
  1034.       aPolyVerbH:= TPolyVerbHdl(NewHandle(SizeOf(TPolyVerbRec)));
  1035.       IF aPolyVerbH<> NIL THEN
  1036.          WITH aPolyRecH^^ DO BEGIN        { ••• See comment 1, below. ••• }
  1037.             fPolyFrame := TRUE;
  1038.             fPolyFill  := FALSE;
  1039.             fPolyClose := FALSE;     { Compare with the result for TRUE ! }
  1040.             f3 := FALSE;
  1041.             f4 := FALSE;
  1042.             f5 := FALSE;
  1043.             f6 := FALSE;
  1044.             f7 := FALSE;
  1045.          END;
  1046.       MoveTo(p^[0].h,p^[0].v);            { ••• See comment 2, below. ••• }
  1047.       PicComment(PolyBegin,0,NIL);
  1048.    {  PicComment(PolyClose,0,NIL);  <<< Only if fPolyClose = TRUE, above! }
  1049.       PicComment(PolySmooth,SizeOf(TPolyVerbRec),Handle(aPolyVerbH));
  1050.       clipRgn := NewRgn;
  1051.       GetClip(clipRgn);
  1052.       ClipRect(zeroRect);
  1053.       FOR i := 1 TO kN DO LineTo(p^[i].h,p^[i].v);
  1054.       { Next, the -crude- QuickDraw approximation of the smoothed polygon, }
  1055.       { invisible for PostScript because of PolyIgnore: }
  1056.       SetClip(clipRgn);
  1057.       PicComment(PolyIgnore,0,NIL);
  1058.       polyRgn := NewRgn;                   { ••• See comment 3, below. ••• }
  1059.       OpenRgn;
  1060.       MoveTo(q^[0].h,q^[0].v);
  1061.       FOR i := 1 TO kM DO LineTo(q^[i].h,q^[i].v);
  1062.       CloseRgn(polyRgn);
  1063.       FrameRgn(polyRgn);         { Or FillRgn, if fPolyFill above is TRUE. }
  1064.       PicComment(PolyEnd,0,NIL);
  1065.       DisposHandle(Handle(aPolyVerbH));
  1066.       DisposeRgn(polyRgn);
  1067.       DisposPtr(Ptr(p));
  1068.       DisposPtr(Ptr(q));
  1069.    END;
  1070. Figure 3—QuickDraw Output    Figure 4—PostScript printern printer output
  1071. Additional Comments and Explanations 
  1072. 1.    The fPolyFrame and fPolyFill fields of the TPolyRec record are self-explanatory. The fPolyClose flag is redundant with the PolyClose picture comment, but is included for the convenience of the LaserWriter driver. It is often misunderstood. It does not mean the polygon is being closed automatically, such as with the PostScript closepath operator; instead, it affects the shape of the smooth curve. Figure 4 shows the result for fPolyClose = FALSE; the start and end point of the polygon is distinguished. In the case of fPolyClose = TRUE, all vertices of the polygon are treated in the same manner, and the resulting curve resembles a circle (in this case).
  1073. 2.    The anonymous fields f3..f7 are reserved and should be set to zero (that is, FALSE).
  1074. 3.    The polygon is drawn at the current pen location when the PolyBegin comment is received. 
  1075. 4.    In general (and in this example), you do not need to open a region, collect the line segments in the region, and draw the polygon through FrameRgn. It is demonstrated here only to prepare you for situations where you want to fill the polygon with a pattern. You cannot open a polygon and use FillPoly, because the PostScript driver “owns” the polygon concept at this point and captures—and ignores—all line drawing between the PolyIgnore and PolyEnd comment. Regions do not interfere with polygons, however, and can be used to paint or fill the polygonal shape. 
  1076. Caveats
  1077. PostScript Level 1 has problems with very large polygons (more than about 1000 points). The workaround is to subdivide the large polygon into several smaller ones.
  1078. You cannot combine the polygon picture comments with other comments such as the rotation comments or the DashedLine comment. It’s just another limitation—no comment. 
  1079. Dashed Lines
  1080. Comments:    DashedLine, DashedStop
  1081. PostScript allows applications to draw precisely dashed lines with a given dash pattern in every direction (see the setdash operator, PostScript Language Reference Manual, Second Edition, page 500). The QuickDraw ersatz of setting the pen pattern appears to be awkward at best; the result depends very much on the direction of the line. Coding correctly dashed lines in QuickDraw is quite a hassle and rather clumsy. This is why the DashedLine and DashedStop picture comments have been provided for applications where dashed lines are important and used frequently. Applications can take advantage of these comments when printing to a PostScript printer.
  1082. The DashedLine comment tells the driver that the line drawing instructions following the comment should be dashed according to the parameters in the TDashedLine structure (see the Appendix). These parameters closely correspond to the parameters passed to the PostScript setdash operator. Only the centered field of the TDashedLine structure is not currently supported by the LaserWriter driver. It should be set to 0 in case support for centering is added in the future.
  1083. Unlike the picture comments for text rotation or even polygon smoothing, the DashedLine picture comment should not be supported by a non-PostScript driver. The only way to include representations of dashed lines with and without usage of the DashedLine picture comment is to make the following assumption: If the DashedLine comment is supported, then the printer is a PostScript printer, and the PostScriptBegin/PostScriptEnd bracket may be used to hide the QuickDraw imaging from the printer. Remember that non-PostScript printer drivers must not ignore QuickDraw imaging within PostScriptBegin and PostScriptEnd!
  1084. But we still need a trick to hide the line drawing instructions within the DashedLine – DashedStop bracket from QuickDraw. Here comes the “magic pen mode” to our rescue:
  1085. PROCEDURE DashDemo;
  1086.    CONST
  1087.       magicPen = 23; { the infamous penMode ! }
  1088.       cx = 280;
  1089.       cy = 280;
  1090.       r0 = 200;
  1091.    VAR
  1092.       dashHdl: TDashedLineHdl;
  1093.       i: Integer;
  1094.       a, rad : Extended;
  1095.    BEGIN
  1096.       PenSize(2,2);
  1097.       { First the PostScript picture comment version.  }
  1098.       { The "magic pen mode" 23 makes the line drawing invisible for QuickDraw. }
  1099.       PenMode(magicPen);
  1100.       dashHdl := TDashedLineHdl(NewHandle(SizeOf(TDashedLineRec)));
  1101.       IF dashHdl <> NIL THEN
  1102.          WITH dashHdl^^ DO BEGIN
  1103.             offset := 4;       { just for fun }
  1104.             centered := 0;     { Currently ignored - set to 0. }
  1105.             intervals[0] := 2; { number of interval specs      }
  1106.             intervals[1] := 4; { This means 4 points on ...    }
  1107.             intervals[2] := 6; { ... and 6 points off.         }
  1108.             PicComment(DashedLine, SizeOf(TDashedLineRec), Handle(dashHdl));
  1109.          END;
  1110.       rad := 3.14159 / 180;    { Conversion degrees -> radians. }
  1111.       FOR i := 0 TO 9 DO BEGIN { Draw some dashed lines. }
  1112.          a := i * 20 * rad;
  1113.          MoveTo(cx, cy);
  1114.          Line(round(r0 * cos(a)), - round(r0 * sin(a)));
  1115.       END;
  1116.       PicComment(DashedStop, 0, NIL); { That's enough! }
  1117.       DisposHandle(Handle(dashHdl));
  1118.       PenMode(srcOr);  { No magic any more. }
  1119.       { Now, the QuickDraw version. The PostScript driver must ignore it, }
  1120.       { so we enclose it between PostScriptBegin and PostScriptEnd comments.}
  1121.       PicComment(PostScriptBegin, 0, NIL);
  1122.       PenSize(2,2);
  1123.       FOR i := 0 TO 9 DO BEGIN
  1124.          MoveTo(cx,cy);
  1125.          DashedQDLine(round(r0 * cos(i * 20 * rad)),
  1126.                     - round(r0 * sin(i * 20 * rad)), dashHdl);
  1127.       END;
  1128.       PicComment(PostScriptEnd,0,NIL);
  1129.    END;
  1130. By the way: The DashedQDLine procedure is intentionally missing. It’s not precisely the subject of this Note, and thus, again, is left as a spare-time exercise for the reader.
  1131. Caveat
  1132. As mentioned earlier, the current version of the PostScript LaserWriter driver produces poor results when the DashedLine picture comment is applied to polygons. Just don’t do it!
  1133. Fractional Line Width
  1134. Comment:    SetLineWidth
  1135. QuickDraw’s design is based on a fixed 72-dpi resolution. Even when printing to a high-resolution device, the Printing Manager presents the printing grafPort, corresponding to the printable area of the page, in the integer-valued QuickDraw coordinate system with 72 dpi. Applications can use PrGeneral to image at higher device resolutions (see Inside Macintosh Volume V, page 410), but this is useful mainly for immediate printing. As a consequence, lines are usually always at least 1/72 inch wide, corresponding to the smallest pen size (1,1). For a 300-dpi device like the LaserWriter, this is disappointing.
  1136. The SetLineWidth comment allows an application to set the width of a line to any fractional value. A value of 1/4 approximately corresponds to a “hairline” on a 300 dpi LaserWriter. Curiously (but conveniently), a QuickDraw Point structure is passed in the PicComment’s data handle, the vertical coordinate representing the denominator, and the horizontal coordinate the numerator of the fraction.
  1137. Unfortunately, it is not implemented in all high-resolution QuickDraw printers; and if it is (as in the LaserWriter SC), it works differently than in PostScript printer drivers. Moreover, there is no possibility to include alternative imaging instructions in case SetLineWidth is not supported. While this is not much of a loss for hairlines, it prevents us from using the comment for fractional widths > 1, where the alternative would be to include a PenSize call with rounded arguments. Another drawback may be that, allegedly, there are plotter drivers out there that abuse this comment to set the pen color—clearly an unpleasant situation.
  1138. The difference in the implementation of the SetLineWidth comment between the PostScript LaserWriter driver and the LaserWriter SC appears as soon as SetLineWidth is used for the second time. The PostScript driver keeps an internal line scaling factor; this factor is initialized to 1.0 when a job is started. Each number passed through SetLineWidth is multiplied by the current internal scaling factor to get the effective scaling factor for the pen size. The LaserWriter SC driver, on the other hand, replaces its current scaling factor for the pen size completely by the new value passed through SetLineWidth. In order to support both implementations, you must always use an additional SetLineWidth step in order to reset the PostScript driver line width to 1.0, before scaling to the new value. 
  1139. Example
  1140. Let’s say you have set the line width to 0.25, and want to replace it by a line width of 0.5. The following two SetLineWidth comments will have the desired effect on both PostScript (PS) and QuickDraw (QD) drivers that implement the SetLineWidth comment. You don’t care about the temporary line width of 4.0 on the QuickDraw driver.
  1141.     Current Line Width    Parameter Passed    New Line Width
  1142.     PS driver    QD driver    in SetLineWidth    PS Driver    QD Driver
  1143.     0.25    0.25    4/1    1.0    4.0
  1144.     1.0    4.0    1/2    0.5    0.5
  1145. The following sample code gives the expected results only on a PostScript LaserWriter and on QuickDraw printer drivers that have the SetLineWidth comment implemented.
  1146. PROCEDURE SetNewLineWidth(oldWidth,newWidth: TLineWidth);
  1147.    VAR
  1148.       tempWidthH: TLineWidthHdl;
  1149.    BEGIN
  1150.       tempWidthH := TLineWidthHdl(NewHandle(SizeOf(TLineWidth)));
  1151.       { If tempWidthH = NIL we are screwed anyway. }
  1152.       tempWidthH^^.v := oldWidth.h;
  1153.       tempWidthH^^.h := oldWidth.v;
  1154.       PicComment(SetLineWidth,SizeOf(TLineWidth),Handle(tempWidthH));
  1155.       tempWidthH^^ := newWidth;
  1156.       PicComment(SetLineWidth,SizeOf(TLineWidth),Handle(tempWidthH));
  1157.       DisposHandle(Handle(tempWidthH));
  1158.    END;
  1159. PROCEDURE LineWidthDemo;
  1160.    CONST
  1161.       y0 = 50;  { topleft of demo }
  1162.       x0 = 50;
  1163.       d0 = 440; { length of horizontal lines }
  1164.       e0 = 5;   { distance between lines }
  1165.       kN = 5;   { number of lines }
  1166.    VAR
  1167.       oldWidth,newWidth: TLineWidth;  { actually a "Point" }
  1168.       i,j,y: Integer;
  1169.    BEGIN
  1170.       PenNormal;
  1171.       y := y0;
  1172.       SetPt(oldWidth,1,1);             { initial linewidth = 1.0 }
  1173.       FOR i := 1 TO 5 DO BEGIN
  1174.          SetPt(newWidth,4,i);
  1175.                   { want to set it to i/4 = 0.25, 0.50, 0.75 ... }
  1176.          SetNewLineWidth(oldWidth,newWidth);
  1177.          MoveTo(x0, y);
  1178.          Line(d0, 0);
  1179.          y := y + e0;
  1180.          oldWidth := newWidth;
  1181.       END;
  1182.    END;
  1183. •A Slight Imperfection
  1184. •If you experiment with the above code and draw a whole series of hairlines, you will see (depending on the values of e0 and kN) that certain lines appear thicker than they should be. This is due to rasterization effects in PostScript’s scan conversion algorithm when the line width is close to the device pixel size. In many cases, the PostScript LaserWriter driver tries to compensate for this by rounding coordinates to the 300-dpi grid. If you include SetLineWidth (or, by the way, DashedLine) picture comments, however, this does not work. PostScript Level 2 addresses this problem by means of an optional stroke adjustment feature (see the PostScript Language Reference Manual, Second Edition, pages 322 and 515).
  1185. Graphics Rotation
  1186. Comments:    RotateBegin, RotateCenter, RotateEnd
  1187. Like the picture comments discussed earlier in this Note in the section “Text Rotation,” the graphics rotation picture comments provide a method of rotating QuickDraw objects on PostScript devices. Instead of having QuickDraw perform the rotation, the printer driver rotates the entire PostScript coordinate space so that everything drawn between RotateBegin and RotateEnd will be rotated on the printer itself. This includes text drawing! You specify the center of rotation with RotateCenter and the angle of the rotation, together possibly with horizontal or vertical flipping, through the TRotation record (see the interface definitions in the Appendix).
  1188. Unlike text rotation, you must insert the RotateCenter comment and pass the relative offset to the center of rotation before you use the RotateBegin picture comment. The point passed to RotateCenter specifies the offset from the anchor point of the first object drawn after RotateBegin to the desired center of rotation. Once you set up the rotation parameters with RotateCenter and RotateBegin, you can draw the graphics objects you want to rotate.
  1189. Bad news: In order to include a QuickDraw representation of the rotated objects in case the rotation comments are not supported, we have to assume (again) that only PostScript drivers implement these comments. The only way to hide the QuickDraw substitute from the driver is to surround it by PostScriptBegin and PostScriptEnd comments; and, similarly to the DashedLine comment, we need to use the “magic pen mode” (23) to hide the unrotated drawing between RotateBegin and RotateEnd from QuickDraw. The following sample demonstrates this:
  1190. PROCEDURE QDRotatedRect(r: Rect; ctr: Point; angle: Integer);
  1191.    BEGIN
  1192.       { An exercise again - this one is easy ...             }
  1193.       { Rotates the four points of the rectangle by "angle"  }
  1194.       { around the center obtained by adding the point "ctr" }
  1195.       { as offset to r.topLeft, and draws the rotated Rect.  }
  1196.    END;
  1197. PROCEDURE PSRotatedRect(r: Rect; offset: Point; angle: Integer);
  1198. { Does the rectangle rotation for the PostScript LaserWriter driver. }
  1199. { Uses the RotateCenter, RotateBegin and RotateEnd picture comments, }
  1200. { and the "magic" pen mode 23 to hide the drawing from QuickDraw.    }
  1201.    CONST
  1202.       magicPen = 23;
  1203.    VAR
  1204.       rInfo: TRotationHdl;
  1205.       rCenter: TCenterHdl;
  1206.       oldPenMode: Integer;
  1207.    BEGIN
  1208.       rInfo := TRotationHdl(NewHandle(SizeOf(TRotationRec)));
  1209.       rCenter := TCenterHdl(NewHandle(SizeOf(TCenterRec)));
  1210.       IF (rInfo = NIL) OR (rCenter = NIL) THEN DebugStr('NewHandle failed');
  1211.       WITH rInfo^^ DO BEGIN
  1212.          rFlip := 0;
  1213.          rAngle := - angle;
  1214.          rAngleFixed := BitShift(LongInt(rAngle),16);
  1215.       END;
  1216.       WITH rCenter^^ DO BEGIN
  1217.          x := Long2Fix(offset.h);
  1218.          y := Long2Fix(offset.v);
  1219.       END;
  1220.       MoveTo(r.left,r.top);
  1221.       FlushGrafPortState;
  1222.       PicComment(RotateCenter,SizeOf(TCenterRec),Handle(rCenter));
  1223.       PicComment(RotateBegin,SizeOf(TRotationRec),Handle(rInfo));
  1224.       oldPenMode := thePort^.pnMode;
  1225.       PenMode(magicPen);
  1226.       FrameRect(r);
  1227.       PenMode(oldPenMode);
  1228.       PicComment(RotateEnd,0,NIL);
  1229.       DisposeHandle(Handle(rInfo));
  1230.       DisposeHandle(Handle(rCenter));
  1231.    END;
  1232. PROCEDURE RotateDemo;
  1233.    CONST
  1234.       angle = 30;
  1235.    VAR
  1236.       spinRect: Rect;
  1237.       delta: Point;
  1238.    BEGIN
  1239.       SetRect(spinRect,100,100,300,200);
  1240.       WITH spinRect DO SetPt(delta,(right - left) DIV 2,(bottom - top) DIV 2);
  1241.       PenSize(2,2);
  1242.       PenPat(ltGray);
  1243.       FrameRect(spinRect); { show the unrotated square }
  1244.       PenNormal;
  1245.       PSRotatedRect(spinRect,delta,angle);
  1246.  { QuickDraw equivalent of the rotated object, hidden from PostScript driver  }
  1247.  { because of PostScriptBegin and PostScriptEnd }
  1248.       PicComment(PostScriptBegin,0,NIL);
  1249.       QDRotatedRect(spinRect,delta,angle);
  1250.       PicComment(PostScriptEnd,0,NIL);
  1251.    END;
  1252. PostScript Comments
  1253. Comments:    PostScriptBegin, PSBeginNoSave, PostScriptEnd, PostScriptHandle
  1254. The PostScript comments tell the picture interpreter (usually the LaserWriter driver) that the application is going to communicate with the LaserWriter directly using PostScript code instead of QuickDraw. All QuickDraw drawing instructions between the PostScriptBegin and PostScriptEnd picture comments are ignored. The driver sends the PostScript text contained in the PostScriptHandle data to the printer with no preprocessing and no error checking. When the application is finished sending PostScript, the PostScriptEnd comment tells the printer driver to resume normal QuickDraw mode. The driver uses the PostScript save and restore operators to preserve the state of the PostScript interpreter across the section enclosed by PostScriptBegin and PostScriptEnd. Some applications do not want to restore the previous state of the PostScript interpreter after including their PostScript code; for these situations, the PSBeginNoSave comment is a replacement for PostScriptBegin that does not preserve the state. Clearly, this comment should be used with extreme caution.
  1255. Some state information may be stored in global variables, so nesting PostScriptBegin (or PSBeginNoSave) and PostScriptEnd comments is not allowed.
  1256. The PostScriptHandle comment gives developers direct access to PostScript from applications. Instead of having the LaserWriter driver convert QuickDraw calls into the corresponding PostScript code, the application can generate its own PostScript, and transmit it to the printer or include it in a picture through the data handle of the PicComment procedure. The handle contains pure ASCII text; the valid length of the data is specified in the PicComment’s size parameter. Don’t forget to terminate the PostScript text at least with a space character, or better with a carriage return (ASCII $0D), so that it is separated from the following PostScript instructions (either yours, or the printer driver’s).
  1257. You must still use PostScriptBegin (or PSBeginNoSave) and PostScriptEnd around PostScriptHandle comments or the LaserWriter driver will not properly save and restore the PostScript drawing environment. 
  1258. As with all picture comments, the handle you pass belongs to you and you must dispose of it when you’re finished with it.
  1259. PROCEDURE PostScriptLine(s: Str255);
  1260. { A utility procedure to transmit a string of PostScript code through }
  1261. { the PostScriptHandle picture comment to the PostScript printer.     }
  1262. { It should be called only between PostScriptBegin and PostScriptEnd  }
  1263. { picture comments. }
  1264.    VAR
  1265.       h: Handle;
  1266.    BEGIN
  1267.       h := NewHandle(256);
  1268.       IF h = NIL THEN DebugStr('NewHandle failed');
  1269.       BlockMove(@s[1],h^, Length(s));
  1270.       PicComment(PostScriptHandle, Length(s), h);
  1271.       h^^ := 13;
  1272.       PicComment(PostScriptHandle, 1, h); { add a carriage return }
  1273.       DisposeHandle(h);
  1274.    END;
  1275. PROCEDURE PostScriptComments;
  1276.    BEGIN
  1277.       { First, the simple example: }
  1278.       PicComment(PostScriptBegin,0,NIL);
  1279.       PostScriptLine('100 100 moveto 0 100 rlineto 100 0 rlineto ');
  1280.       PostScriptLine('0 -100 rlineto -100 0 rlineto');
  1281.       PostScriptLine('stroke');
  1282.       MoveTo(30,30);
  1283.       DrawString('This text does not appear on PostScript devices');
  1284.       PicComment(PostScriptEnd,0,NIL);
  1285.       { Now, a new PostScript definition you want to keep in the     }
  1286.       { userdict. If you used PostScriptBegin, the definition would  }
  1287.       { be lost when PostScriptEnd is encountered, because the state }
  1288.       { previous to the PostScriptBegin comment would be restored.   }
  1289.       PicComment(PSBeginNoSave,0,NIL);
  1290.       PostScriptLine('userdict begin');
  1291.       PostScriptLine('/myFrameRect {');
  1292.       PostScriptLine('250 250 moveto 0 100 rlineto');
  1293.       PostScriptLine('200 0 rlineto 0 -100 rlineto -200 0 rlineto ');
  1294.       PostScriptLine('stroke } def');
  1295.       PostScriptLine('end');
  1296.       PicComment(PostScriptEnd,0,NIL);
  1297.       { Let's test to see if the definition from above is still avail-}
  1298.       { able. This assumes that no font downloading has occurred.     }
  1299.       PicComment(PostScriptBegin,0,NIL);
  1300.       PostScriptLine('//userdict /myFrameRect get exec ');
  1301.       PicComment(PostScriptEnd,0,NIL);
  1302.    END;
  1303. Caveat
  1304. If you choose to use PostScript directly in your pictures, be very careful not to make assumptions about Apple’s "md" dictionary (essentially the contents of the former LaserPrep file). Otherwise, your pictures will not print correctly with future versions of the PostScript LaserWriter driver. Also, be aware of compatibility problems within the PostScript world, and watch out for printers with PostScript Level 1 and PostScript Level 2 interpreters, and “PostScript-compatible” printers (PostScript clones).
  1305. FormsPrinting Picture Comments
  1306. Comments:    FormsPrinting, EndFormsPrinting
  1307. The FormsPrinting comment tells the PostScript LaserWriter driver not to clear its page buffer after printing a page. EndFormsPrinting turns this mode off. When the page is completed, the application must erase the areas that need to be updated and draw the new information. The graphics that make up the form are drawn only once per page, which may improve performance. Currently, you need to write special printing code for the PostScript LaserWriter driver if you want to use this comment. 
  1308. (More or Less) Obsolete PostScript Picture Comments
  1309. Comments:    SetGrayLevel,
  1310.     TextIsPostScript, ResourcePS, PostScriptFile
  1311. The SetGrayLevel picture comment was designed to provide access to the PostScript setgray operator while still drawing with QuickDraw in black-and-white mode. In practice, this turned out to be not so useful, however. For most drawing operations, the printer driver sets the gray level to match the foreground color currently stored in the printing grafPort, and the effect of the SetGrayLevel comment is often unpredictable. If direct access to the PostScript setgray operator seems nevertheless desirable, it is easy to include the instruction in a PostScriptHandle comment.
  1312. The TextIsPostScript picture comment takes all the text coming through standard QuickDraw text drawing calls (DrawChar, DrawString, DrawText, and anything else that eventually calls the StdText bottleneck), and interprets it as a PostScript program. There is no good reason to use this picture comment, but there is one important reason not to use it: Printer drivers that do not deal with the TextIsPostScript comment will print the PostScript text instead of interpreting it! If you need to transmit pure PostScript code directly to a printer that understands it, use the PostScriptHandle comment, and include a QuickDraw representation for all other printer drivers.
  1313. The ResourcePS picture comment loads PostScript code from a specified resource. The resource file is expected to be open at the time that the ResourcePS comment is used. Under background printing, there are no guarantees the file will still be open when the Printing Manager needs it. For this reason alone, you should forget about this comment. If you want to keep PostScript instructions in a resource, it is easy to write a small routine that loads the resources and sends their contents using the PostScriptHandle comment described earlier in this Note.
  1314. PostScriptFile has the same problems as ResourcePS described above. Basically, the Printing Manager cannot guarantee that the file will be available when it’s needed.
  1315. Appendix: Pascal Interface for Picture Comments
  1316. (File PicComments.p)
  1317. CONST
  1318.    TextBegin = 150;
  1319.    TextEnd = 151;
  1320.    StringBegin = 152;
  1321.    StringEnd = 153;
  1322.    TextCenter = 154;
  1323.    LineLayoutOff = 155;
  1324.    LineLayoutOn = 156;
  1325.    ClientLineLayout = 157;
  1326.    PolyBegin = 160;
  1327.    PolyEnd = 161;
  1328.    PolyIgnore = 163;
  1329.    PolySmooth = 164;
  1330.    PolyClose = 165;
  1331.    DashedLine = 180;
  1332.    DashedStop = 181;
  1333.    SetLineWidth = 182;
  1334.    PostScriptBegin = 190;
  1335.    PostScriptEnd = 191;
  1336.    PostScriptHandle = 192;
  1337.    PostScriptFile = 193;
  1338.    TextIsPostScript = 194;
  1339.    ResourcePS = 195;
  1340.    PSBeginNoSave = 196;
  1341.    SetGrayLevel = 197;
  1342.    RotateBegin = 200;
  1343.    RotateEnd = 201;
  1344.    RotateCenter = 202;
  1345.    FormsPrinting = 210;
  1346.    EndFormsPrinting = 211;
  1347.   
  1348.    tJusNone = 0;           { values for the tJus field of the TTxtPicRec record }
  1349.    tJusLeft = 1;
  1350.    tJusCenter = 2;
  1351.    tJusRight = 3;
  1352.    tJusFull = 4;
  1353.    
  1354.    tFlipNone = 0;         { values for the tFlip field of the TTxtPicRec record }
  1355.    tFlipHorizontal = 1;
  1356.    tFlipVertical = 2;
  1357. TYPE
  1358.    TTxtPicHdl = ^TTxtPicPtr;
  1359.    TTxtPicPtr = ^TTxtPicRec;
  1360.    TTxtPicRec = PACKED RECORD
  1361.                    tJus  : Byte;
  1362.                    tFlip : Byte; 
  1363.                    tAngle: Integer;     { clockwise rotation in degrees 0..360 }
  1364.                    tLine : Byte;        { Unused/Ignored }
  1365.                    tCmnt : Byte;        { reserved }
  1366.                    tAngleFixed: Fixed;  { same as "tAngle" in Fixed precision  }
  1367.                END; { TTxtPicRec }
  1368.    TRotationHdl = ^TRotationPtr;
  1369.    TRotationPtr = ^TRotation;
  1370.    TRotationRec = RECORD
  1371.                     rFlip: Integer;
  1372.                     rAngle: Integer;    { clockwise rotation in degrees 0..360 }
  1373.                     rAngleFixed: Fixed; { same as "rAngle" in Fixed precision  }
  1374.                  END; { TRotationRec }
  1375.    TCenterHdl = ^TCenterPtr;
  1376.    TCenterPtr = ^TCenter;
  1377.    TCenterRec = RECORD  {offset from current pen location to center of rotation}
  1378.                    y: Fixed;
  1379.                    x: Fixed;
  1380.                 END; { TCenterRec }
  1381.    TPolyVerbHdl = ^TPolyVerbPtr;
  1382.    TPolyVerbPtr = ^TPolyVerbRec;
  1383.    TPolyVerbRec = PACKED RECORD
  1384.                      f7,f6,f5,f4, f3,     { reserved }
  1385.                      fPolyClose,          { TRUE = smoothing across endpoint.}
  1386.                      fPolyFill,           { TRUE = Polygon should be filled. }
  1387.                      fPolyFrame: BOOLEAN; { TRUE = Polygon should be framed. }
  1388.                   END;
  1389.    TDashedLineHdl = ^TDashedLinePtr;
  1390.    TDashedLinePtr = ^TDashedLineRec;
  1391.    TDashedLineRec = PACKED RECORD
  1392.                        offset   : SignedByte;  { offset into pattern for }                                   { first dash              }
  1393.                        centered : SignedByte;  { (Ignored)               }
  1394.                        intervals: ARRAY [0..5] { Array of dash intervals }
  1395.                                   OF SignedByte; { intervals[0] = number }
  1396.                     END;                         { of interval specs.    }
  1397.    TLineWidthHdl = ^TLineWidthPtr;
  1398.    TLineWidthPtr = ^TLineWidth;
  1399.    TLineWidth    = Point;  { v = numerator, h = denominator. }
  1400.    TClientLLHdl = ^TClientLLPtr;  { used in the ClientLineLayout picture comment }
  1401.    TClientLLPtr = ^TClientLLRec;
  1402.    TClientLLRec = RECORD
  1403.                      chCount : Integer;  { Apply for so many characters. }
  1404.                      major   : Fixed;    { percentage of line layout error to be }
  1405.                                          { distributed among space characters.   }
  1406.                      spcChar : Integer;  { code of character that is to absorb   }
  1407.                                          { the "major" line layout error         }
  1408.                      minor   : Fixed;    { percentage of intercharacter distrib. }
  1409.                      ulLength: Fixed;    { underline length.                     }
  1410.                   END;
  1411. Further Reference:
  1412. •    PostScript Language Reference Manual, Adobe Systems Inc.
  1413. •    Inside Macintosh, Volumes II, V, and VI
  1414. •    LaserWriter Reference Manual, Addison-Wesley
  1415. •    Macintosh Technical Note M.IM.AppPictComments —    
  1416.         Every Picture [Comment] Tells Its Story, Don’t It?
  1417. •    Macintosh Technical Note M.IM.PictAndPrinting —
  1418.         Pictures and the Printing Manager
  1419. •    develop Issue 3, “Meet PrGeneral” by Pete “Luke” Alexander
  1420. Adobe is a trademark of Adobe Systems Incorporated.
  1421. PostScript is a registered trademark of Adobe Systems Incorporated.
  1422. QD 11 - Pictures and Clip Regions
  1423. QuickDraw    
  1424. Revised by:         March 1988
  1425. Written by:    Jennifer Jernigan    January 1986
  1426. This note describes a problem that affects creation of QuickDraw pictures.
  1427. When a GrafPort is created, the fields in the GrafPort are given default values; one of these is the clip region, which is set to the rectangle (–32767, –32767, 32767, 32767). If you create a picture, then call DrawPicture with a destination rectangle that is not the same size as the picFrame without ever changing the default clip region, nothing will be drawn.
  1428. When the picture frame is compared with the destination rectangle and the picture is scaled, the clip region is scaled too. In the process of scaling, the clip region you end up overflows and becomes empty, and your picture doesn’t get drawn. If you call ClipRect(thePort^.portRect) before you record the picture, the picture will be drawn correctly. The clipping on the destination port when playing back the picture is irrelevant: once a picture is incorrectly recorded, it is too late.
  1429. Further Reference:
  1430. •    QuickDraw
  1431. QD 12 - Plotting Small Icons
  1432. QuickDraw    
  1433. Revised by:    James Beninghaus    October 1989
  1434. Written by:    James Beninghaus & Dennis Hescox    August 1989
  1435. This Technical Note discusses the 'SICN' resource format and how to plot one in a GrafPort.
  1436. Changes since August 1989:  Corrected errors in the Pascal code and spruced up the rest.
  1437. Introduction
  1438. Apple first introduced the 'SICN' resource so that the Script Manager could represent which country specific resources are installed in the system by displaying a small icon in the upper right corner of the menu bar.  You can pass a 'SICN' resource to the Notification Manager or Menu Manager, and they will draw it for you automatically—you should continue to let them do so.  However, if you want to draw a small icon in your application’s window, then this Note can help.
  1439. What does a 'SICN' look like?  Following is a 'SICN' representation of a dogcow to help answer this question:
  1440. SICN'            FatBits
  1441. There is reason to believe that this representation is actually a baby dogcow.  Due to the protective nature of parent dogcows, young dogcows are rarely seen.  This one was spotted during a DTS meeting after it drew attention to itself by crying “moo! woof!”.  (Note that this dogcow said “moo! woof!” because it was immature; adult dogcows naturally say, “Moof!”.)
  1442. 'SICN' Resource
  1443. A 'SICN' resource contains any number of small icon bit images.  Each small icon in a 'SICN' list describes a 16 by 16 pixel image and requires 32 bytes of storage.  Like an 'ICN#' resource, there is no count of the number of icons stored in a 'SICN'.  The following 'SICN' resource, in MPW Rez format, contains two small icons:
  1444.     resource 'SICN' (1984, "clarus") {
  1445.         {    /* array: 2 elements */
  1446.             $"00 48 00 B4 00 84 40 52 C0 41 A0 81 9F 8E 8F 18"
  1447.             $"40 18 40 18 47 88 48 48 48 48 44 44 3C 3C 00 00",
  1448.             $"00 48 00 FC 00 FC 40 7E C0 7F E0 FF FF FE FF F8"
  1449.             $"7F F8 7F F8 7F F8 78 78 78 78 7C 7C 3C 3C 00 00"
  1450.         }
  1451.     };
  1452. The Right Tools for the Job
  1453. The Macintosh Toolbox interfaces do not describe all the necessary data structures needed to work with 'SICN' resources.  As shown in the following example, defining the 'SICN' type as an array of 16 short integers and the handles and pointers to this array type make life much easier.
  1454. Pascal
  1455. TYPE
  1456.        SICN        = ARRAY[0 .. 15] of INTEGER;
  1457.        SICNList    = ARRAY[0 .. 0] of SICN;
  1458.        SICNPtr     = ^SICNList;
  1459.        SICNHand    = ^SICNPtr;
  1460. C
  1461. typedef    short       SICN[16];
  1462. typedef    SICN        *SICNList;
  1463. typedef    SICNList    *SICNHand;
  1464. The Missing Count
  1465. The 'SICN' resource does not provide a count to indicate the number of small icons contained within; however, you can easily determine this number by dividing the total size of the resource by the size of a single small icon.
  1466. Pascal
  1467. CONST
  1468.        mySICN      = 1984;
  1469. VAR
  1470.        theSICN     : SICNHand;
  1471.        theSize     : LONGINT;
  1472.        theCount    : LONGINT;
  1473.        theIndex    : LONGINT;
  1474. theSICN := SICNHand(GetResource('SICN', mySICN));
  1475. IF (theSICN <> NIL) THEN BEGIN
  1476.        theSize := GetHandleSize(Handle(theSICN));
  1477.        theCount := theSize DIV sizeof(SICN);
  1478. END;
  1479. C
  1480. #define mySICN         1984
  1481. SICNHand   theSICN;
  1482. long       theSize;
  1483. long       theCount;
  1484. long       theIndex;
  1485. theSICN = (SICNHand) GetResource('SICN', mySICN);
  1486. if (theSICN) {
  1487.        theSize = GetHandleSize((Handle)theSICN);
  1488.        theCount = theSize / sizeof(SICN);
  1489. }
  1490. The Plot 'SICN's
  1491. The example procedure PlotSICN draws one small icon of a 'SICN' resource.  It takes the handle from theSICN and the position in the list from theIndex within the rectangle theRect of the current GrafPort.
  1492. Following is an example call to PlotSICN which plots all the small icons in a resource into the same rectangle:
  1493. Pascal
  1494. SetRect(theRect, 0, 0, 16, 16);
  1495. FOR theIndex := 0 TO theCount-1 DO
  1496.        PlotSICN(theRect, theSICN, theIndex);
  1497. C
  1498. SetRect(&theRect, 0, 0, 16, 16);
  1499. for (theIndex = 0; theIndex < theCount ; ++theIndex)
  1500.        PlotSICN(&theRect, theSICN, theIndex);
  1501. Because PlotSICN uses _CopyBits and _CopyBits can move memory, you should lock the handle to the 'SICN' once the resource is loaded.  Notice that the PlotSICN procedure dereferences the 'SICN' handle, adds an offset, and copies the resulting value.  If the 'SICN' list moves in memory at this time, the bitmap’s baseAddr is useless.
  1502. To play it safe, PlotSICN saves a copy of the master pointer flags associated with the relocatable block, locks the block with a call to _HLock, and restores the flags after calling _CopyBits.  You should never examine, set, or clear these flags directly; you should always use the routines which are provided by the Memory Manager and Resource Manager.  Note that it is not necessary to check the value of the flag after getting it.
  1503. Pascal
  1504. PROCEDURE PlotSICN(theRect: Rect; theSICN: SICNHand; theIndex : INTEGER);
  1505. VAR
  1506.        state       : SignedByte;    { we want a chance to restore original state }
  1507.        srcBits     : BitMap;    { built up around 'SICN' data so we can
  1508.                                       _CopyBits }
  1509. BEGIN
  1510.        { check the index for a valid value }
  1511.        IF (GetHandleSize(Handle(theSICN)) DIV sizeof(SICN)) > theIndex THEN
  1512.        BEGIN
  1513.            { store the resource's current locked/unlocked condition }
  1514.            state := HGetState(Handle(theSICN));
  1515.            { lock the resource so it won't move during the _CopyBits call }
  1516.            HLock(Handle(theSICN));
  1517.            { set up the small icon's bitmap }
  1518.            {$PUSH}
  1519.            {$R-}            { turn off range checking }
  1520.            srcBits.baseAddr := Ptr(@theSICN^^[theIndex]);
  1521.            {$POP}
  1522.            srcBits.rowBytes := 2;
  1523.            SetRect(srcBits.bounds, 0, 0, 16, 16);
  1524.            { draw the small icon in the current grafport }
  1525.            CopyBits(srcBits,thePort^.portBits,srcBits.bounds,theRect,srcCopy,NIL);
  1526.            { restore the resource's locked/unlocked condition }
  1527.            HSetState(Handle(theSICN), state);
  1528.        END;
  1529. END;
  1530. C
  1531. void PlotSICN(Rect *theRect, SICNHand theSICN, long theIndex) {
  1532.        auto    char    state;    /* saves original flags of 'SICN' handle */
  1533.        auto    BitMap    srcBits;    /* built up around 'SICN' data so we can
  1534.                                       _CopyBits */
  1535.        /* check the index for a valid value */
  1536.        if ((GetHandleSize(Handle(theSICN)) / sizeof(SICN)) > theIndex) {
  1537.            /* store the resource's current locked/unlocked condition */
  1538.            state = HGetState((Handle)theSICN);
  1539.            /* lock the resource so it won't move during the _CopyBits call */
  1540.            HLock((Handle)theSICN);
  1541.            /* set up the small icon's bitmap */
  1542.            srcBits.baseAddr = (Ptr) (*theSICN)[theIndex];
  1543.            srcBits.rowBytes = 2;
  1544.            SetRect(&srcBits.bounds, 0, 0, 16, 16);
  1545.            /* draw the small icon in the current grafport */
  1546.            CopyBits(&srcBits,&(*qd.thePort).portBits,&srcBits.bounds,theRect,srcCopy,nil);
  1547.            /* restore the resource's locked/unlocked condition */
  1548.            HSetState((Handle) theSICN, state);
  1549.        }
  1550. }
  1551. That Was Easy
  1552. Now that you’ve seen it done, it looks pretty easy.  With minor modifications, some of the techniques in this Note could also be used to plot a bitmap of any dimension.
  1553. Further Reference:
  1554. •    Inside Macintosh, Volume I, QuickDraw
  1555. •    Inside Macintosh, Volume I, Toolbox Utilities
  1556. •    Inside Macintosh, Volume IV, The Memory Manager
  1557. •    Technical Note M.IM.OffscreenBitMap —
  1558.          Drawing Into an Off-Screen BitMap
  1559. •    Technical Note M.IM.DrawingIcons —
  1560.          Drawing Icons
  1561. QD 13 - Principia Off-Screen Graphics Environments
  1562. QuickDraw    
  1563. Updated by:    Forrest Tanaka    March 1992
  1564. Written by:    Forrest Tanaka    October 1991
  1565. Inspired by:    Jim Friedlander, Rick Blair, and Rich Collyer
  1566. Using Color QuickDraw to draw off screen is a common requirement of applications and other kinds of programs that run on the Macintosh. This Note discusses what Color QuickDraw needs in a graphics environment and how to create one for off-screen drawing. A brief discussion of GWorlds, which are off-screen graphics environments that are set up by the system, is given to help you decide whether to use them or the do-it-yourself techniques described in this Note for setting up an off-screen graphics environment. The author’s intent is to provide concepts and routines for creating an off-screen graphics environment, and also to explain why existing routines for off-screen drawing act as they do.
  1567. Many, many thanks go to Guillermo Ortiz, Konstantin Othmer, Bruce Leak, and Jon Zap for all their expertise on this subject, Rich Collyer, Rick Blair, and Jim Friedlander for paving the way, and especially to all people who inspired this update by asking great off-screen drawing questions.
  1568. Changes since October 1991:  A very embarrassing bug was found in CreateOffScreen and UpdateOffScreen. If you try to create a 16- or 32-bit off-screen graphics environment, you’ll just get a paramErr. It won’t do that now.
  1569. Off-Screening
  1570. The Macintosh, as with every other CPU ever made by Apple, has memory-mapped video. That is, what you see on the screen is just the visual representation of a part of memory that’s reserved for the video hardware (that’s stretching the truth just a bit in the case of the text screens of the original Apple computer, the Apple II line, and the Apple III because there’s also a character generator in those, but the overall process still looks roughly the same). If you change the contents of a memory location in this part of memory, then you’ll see the corresponding location on the screen change when the video hardware draws the next frame or field of video. The resident raster graphics package, QuickDraw in the case of the Macintosh, draws images by stuffing the right values into the right places in the part of memory reserved for the video display. The resulting image on the screen looks like a line or perhaps an oval if you asked QuickDraw to draw a line or an oval, or it could be an entire complex image if you asked QuickDraw to draw one. This is normal, on-screen drawing.
  1571. Because video memory is a part of RAM just like any other part of RAM in the memory map of the Macintosh (or almost like; video memory might exist on a NuBus™ video card, but it’s still RAM), QuickDraw can be told to draw into a part of memory that isn’t reserved for the video hardware, maybe into a part of your own application’s heap. When you tell QuickDraw to draw into a part of memory that’s not reserved for the video hardware, you can’t see any of the results. This is off-screen drawing. There are plenty of perfectly good reasons to do this, such as providing storage for a paint-style document or to smoothly animate an image, but the assumption here is that you have a perfectly good reason to do this so you’re more interested in the “how” of it instead of the “why” of it. If you need to know why, there are several books that cover off-screen drawing and the perfectly good reasons to do such a thing. A good place to start is Scott Knaster’s book, Macintosh Programming Secrets, referenced at the end of this Note.
  1572. This Note is divided into these major sections:
  1573. • The introduction is the part that you’re reading now.
  1574. • “The Building Blocks” provides an overview of the data structures that you need to tell Color QuickDraw to draw off screen.
  1575. • “Building the Blocks” discusses the construction and initialization of these data structures.
  1576. •    “Playing With Blocks” shows an example of the use of these structures to draw off screen.
  1577. •    “Put That Checkbook Away!” discusses some variations of these techniques to handle off-screen drawing for special cases.
  1578. •    “The GWorld Factor” provides a brief overview of GWorlds, how to use them, and how they compare and contrast to the manual techniques that are described in most of this Note.
  1579. Those of you who aren’t quite sure whether to use GWorlds or the do-it-yourself techniques might want to skip ahead for a moment to “The GWorld Factor” just in case doing it yourself is a waste of time. In any case, it’s a good idea to read this whole Note because the concepts are mostly the same whether you’re using GWorlds or not. GWorlds just make the process a lot easier, and they let you take advantage of the 8•24 GC video card. But, we’re not in that section of the Note yet.
  1580. The Building Blocks
  1581. Before you can tell QuickDraw to draw off of the screen, you’ll need to build three major data structures: a CGrafPort, a PixMap, and a GDevice. You’ll also need a couple of tables that define the colors involved with drawing to and copying from the off-screen image: the color table and the inverse table. Of course, you’ll need the pixel image itself, which is often called the “pixel buffer” or the “image buffer” or the “off-screen buffer” or just “the buffer.” It’s always called the “pixel image” in this Note. It doesn’t necessarily buffer anything anyway.
  1582. The CGrafPort
  1583. A CGrafPort describes a drawing environment, and it’s the color version of the GrafPort structure that’s described on pages 147 through 155 in the QuickDraw chapter of Inside Macintosh Volume I. The drawing environment consists of, among other things, the size and location of the graphics pen, the foreground and background colors to use when something is drawn, the pattern to use, the region to clip all drawing to, and the portion of a pixel image that the CGrafPort logically exists in. Any initialized CGrafPort or GrafPort can be set as the current port through the _SetPort routine. The current port is a set of parameters that are implicitly passed to most QuickDraw routines.
  1584. The most important reason to build a new CGrafPort when you draw off screen rather than using an existing CGrafPort is so that switching between drawing to an off-screen graphics environment and drawing to one or more windows (each of which is an extended GrafPort or CGrafPort structure) on the screen is very easy. Some people use just one CGrafPort to share between on-screen and off-screen graphics environments, and switch their PixMap structures to switch between drawing on screen and drawing off screen. That does work, but if the off-screen and on-screen graphics environments have a different clipRgn, visRgn, pen characteristic, portRect, or any other characteristics that are different, then those must be switched at that time too. If you instead create a CGrafPort that’s dedicated to one graphics environment, then a simple call to _SetPort effectively switches all these things for you at once. That’s why every window on the screen comes with its own port. A simple call to _SetPort switches between the characteristics of each window even if each window has radically different drawing characteristics.
  1585. The CGrafPort data structure is more completely described in the “Color QuickDraw” chapter of Inside Macintosh Volume V, pages 49 through 52, and in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-12 through 16-13.
  1586. The PixMap
  1587. A pixel image alone is just a formless blob of memory. Pixel maps, defined by the PixMap structure, describe pixel images, giving them a form and structure that’s suitable for Color QuickDraw to draw into them and copy from them. The PixMap structure tells you the dimensions and location in memory of the pixel image, its coordinate system, and the depth and format of the pixels. Pixel maps that describe indexed-color pixel images additionally describe the colors that are represented by the values of the pixels in the pixel image. This is done through the color table, also known as the color look-up table or CLUT. Color tables are attached to pixel maps through their pmTable field. Direct-color pixel images have pixel values that describe their own colors, and so color tables aren’t needed for those.
  1588. The PixMap structure is described in the “Color QuickDraw” chapter of Inside Macintosh Volume V, pages 52 through 55, and in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-11 through 16-12. The concept of direct-color and indexed-color pixels is described in this same chapter on pages 16-16 through 16-18, and also in the “Color QuickDraw” chapter of the same volume on pages 17-4 through 17-10.
  1589. The GDevice
  1590. Graphics devices, defined by the GDevice structure, describe color environments. They’re the most misunderstood data structure when it comes to off-screen graphics environments for three major reasons: first, they’re not originally documented as being relevant to humans; second, they look as though they’re only for screens; and third, it looks as though color tables describe color environments. We can dispose of these myths here: graphics devices are documented as being useful to humanity in this Note at least; they’re critically important for both on-screen and off-screen drawing; and color tables describe the colors in pixel images, not color environments.
  1591. What’s all this about color environments? In theory, there are virtually three hundred trillion colors available with Color QuickDraw through the 48-bit RGBColor record. In reality, there are never this many colors available, and in fact there might be only two. Color QuickDraw maps the theoretical color that you specify to the pixel value of the closest available color in the current color environment. This can be done with a color table, but that’s not very efficient. Finding the closest available color to an RGBColor in a color table means searching the entire color table for that one closest color. If that’s done just once, then performance isn’t much of an issue, but if it’s done many times, the performance hit could be significant. A very bad case of this is _CopyBits, where every pixel value in the source image is converted to an RGBColor by looking it up in the color table of the source PixMap. If the color table of the destination PixMap had to be searched to find the closest available color for every pixel in the source PixMap, then the performance of even the most straightforward _CopyBits call could be a lot slower than it has to be.
  1592. To avoid this performance hit, the current GDevice provides an inverse table and a device type which are used to determine the available set of colors. Inverse tables are anticolor tables. Where color tables give you a color for a given pixel value, inverse tables give you a pixel value for a given color. Every conceivable color table has a corresponding conceivable inverse table, just as every positive real number has a corresponding negative real number, or every Mr. Spock has a corresponding Mr. Spock with a goatee. The device type specifies whether the color environment uses the indexed-color, fixed-color, or direct-color model. In the direct-color model, the inverse table is empty. Only the indexed-color and direct-color models are described in this Note.
  1593. When you specify a color in an indexed-color environment, Color QuickDraw takes the RGBColor specification and converts it into a value that can be used as an index into the inverse table of the current GDevice. To do this conversion, Color QuickDraw takes the top few significant bits of each color component and combines them into part of a 16-bit word, blue bits in the least significant bits, green bits right above it, and the red bits right above green bits. Any unused bits are in the most significant bits of the 16-bit word. The resulting 16-bit word is used as an index into the inverse table. The value in the inverse table at that index is the pixel value which best represents that color in the current color environment. The number of bits of each component that are used is determined by what’s called the “resolution” of the inverse table. Almost always, the resolution of an inverse table is four bits, meaning the most significant four bits of each component are used to form the index into the inverse table. Figure 1 shows how an RGBColor record is converted to an index into an inverse table when the inverse-table resolution is four.
  1594. Figure 1  Conversion of RGBColor Record to Inverse-Table Index
  1595. The same process is used when _CopyBits is called with an indexed-color destination. Each pixel in the source pixel image is converted to an RGBColor either by doing a table look-up of the source pixel map’s color table if the source pixel image uses indexed colors, or by expanding the pixel value to an RGBColor record if the source pixel image uses direct colors. The resulting RGBColor is then used to look up a pixel value in the inverse table of the current GDevice, and this pixel value is put into the destination pixel image.
  1596. If you specify a color in a direct-color environment, then the resulting RGBColor is converted to a direct pixel value by the processes that are shown on pages 17-6 through 17-9 of the “Color QuickDraw” chapter of Inside Macintosh Volume VI.
  1597. Usually, inverse-table look-up involves an extra step to find what are called “hidden colors” using proprietary information that’s stored at the end of the inverse table. With an inverse-table resolution of four, only 16 shades of any particular component can be distinguished, and that’s often not enough. An inverse table with a resolution of five is much larger, but it still only gives you 32 shades of any component. Hidden colors are looked up after the normal inverse-table look-up to give a much more accurate representation of the specified color in the current color environment than the inverse-table look-up alone can produce. Sometimes, most notably when the arithmetic transfer modes are used or if dithering is used, the hidden colors are ignored.
  1598. When a new color table is assigned to a PixMap or when its existing color table is modified, then a new corresponding inverse table should be generated for the GDevice that’ll be used when drawing into that environment. Normally, this happens automatically without you having to do any more than inform Color QuickDraw of the change. This is described in more detail in  “Changing the Off-Screen Color Table”  later in this Note.
  1599. Graphics devices are documented in the “Graphics Devices” chapter of Inside Macintosh Volume VI which supersedes the “Graphics Devices” chapter of Inside Macintosh Volume V. They’re also discussed in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-13 through 16-14. The inverse-table mechanism is described in the “Color Manager” chapter of Inside Macintosh Volume V, pages 137 through 139.
  1600. All Together Now
  1601. There are a lot of different ways to put the three structures together, and this Note discusses the architecture that’s shown in Figure 2. This architecture is  useful when you want a simple, atomic, off-screen graphics environment.
  1602. Figure 2  Relationships Between Structures for Off-Screen Drawing
  1603. Notice that there’s no way to get to the GDevice from the CGrafPort, nor is there a way to get to the CGrafPort from the GDevice, though the PixMap can be found through either one. Your application must keep track of both the CGrafPort and the GDevice.
  1604. Building the Blocks
  1605. As with just about any algorithm, there are many ways to put the different structures together that form an off-screen graphics environment. This section covers just one way to build the architecture that’s shown in Figure 2.
  1606. Building the CGrafPort
  1607. The CGrafPort structure is the easiest one to put together because the _OpenCPort routine initializes so many of the fields of the CGrafPort structure for you. It also allocates and initializes the structures that are attached to every CGrafPort, such as the visRgn, clipRgn, grafVars handle, and so forth. Most of these are initialized with values that are fine for general purposes, but the visRgn, clipRgn, and portRect fields should be set to the desired boundary rectangle of the off-screen graphics environment. What follows is an overview of each of the fields that you have to worry about when you’re setting up a CGrafPort for drawing off screen.
  1608. portPixMap    handle to the off-screen PixMap. _OpenCPort initializes this field to a copy of the PixMap that’s attached to the gdPMap field of the current GDevice. An overview of setting up this PixMap for drawing off screen is given in  “Building the PixMap” later in this Note.
  1609. portRect    specifies the rectangular area of the associated pixel image that this CGrafPort controls. This field should be set to the desired rectangular area of the off-screen image because _OpenCPort doesn’t necessarily initialize it to this size. Usually, the top-left corner of this rectangle has the coordinates (0, 0), but not necessarily so.
  1610. visRgn    handle to the region that specifies the visible area into which you can draw. _OpenCPort doesn’t necessarily initialize it to the size of the off-screen image, so it should be set to the same size and coordinates as the portRect and left at that. This field is more important for windows because parts of them can be hidden by other windows.
  1611. clipRgn    handle to the region that specifies the logical area into which you can draw. _OpenCPort initializes it to cover the entire QuickDraw coordinate plane. It’s usually a good idea to set it to the same size and coordinates as the portRect to avoid problems if the clipRgn is scaled or translated, which causes its signed integer coordinates to overflow and turn it into an empty region. One of the most common cases of this occurs when a picture that’s created in this CGrafPort is drawn into a destination rectangle that’s any larger than or translated from the original picture frame. Everything in the picture, including the clip region, is scaled to fit the destination rectangle. If the clip region covers the entire QuickDraw coordinate plane, then its coordinates overflow their signed integer bounds, and the clip region becomes logically empty. The result is that nothing is drawn.
  1612. The CreateOffScreen routine in Listing 1 creates an off-screen graphics environment, given a boundary rectangle, pixel depth, and color table, and it returns a new off-screen CGrafPort and GDevice, along with an error code. The desired pixel depth in bits per pixel is given in the depth parameter. If the pixel depth is eight or less, then an indexed-color graphics environment is created and a color table is required in the colors parameter. If the pixel depth is 16 or 32 bits per pixel and 32-Bit QuickDraw is available, then a direct-color graphics environment is created and the colors parameter is ignored. If 32-Bit QuickDraw isn’t available, then a pixel depth of 16 or 32 bits per pixel results in CreateOffScreen doing nothing more than returning a parameter error. A description of CreateOffScreen is given following the listing.
  1613. MPW Pascal Listing 1
  1614. FUNCTION CreateOffScreen(
  1615.    bounds:         Rect;       {Bounding rectangle of off-screen}
  1616.    depth:          Integer;    {Desired number of bits per pixel in off-screen}
  1617.    colors:         CTabHandle; {Color table to assign to off-screen}
  1618.    VAR retPort:    CGrafPtr;   {Returns a pointer to the new CGrafPort}
  1619.    VAR retGDevice: GDHandle    {Returns a handle to the new GDevice}
  1620.    ): OSErr;
  1621.    CONST
  1622.       kMaxRowBytes = $3FFE; {Maximum number of bytes in a row of pixels}
  1623.    VAR
  1624.       newPort:     CGrafPtr;     {Pointer to the new off-screen CGrafPort}
  1625.       newPixMap:   PixMapHandle; {Handle to the new off-screen PixMap}
  1626.       newDevice:   GDHandle;     {Handle to the new off-screen GDevice}
  1627.       qdVersion:   LongInt;      {Version of QuickDraw currently in use}
  1628.       savedPort:   GrafPtr;      {Pointer to GrafPort used for save/restore}
  1629.       savedState:  SignedByte;   {Saved state of color table handle}
  1630.       bytesPerRow: Integer;      {Number of bytes per row in the PixMap}
  1631.       error:       OSErr;        {Returns error code}
  1632. BEGIN
  1633.    (* Initialize a few things before we begin *)
  1634.    newPort := NIL;
  1635.    newPixMap := NIL;
  1636.    newDevice := NIL;
  1637.    error := noErr;
  1638.    (* Save the color table’s current state and make sure it isn’t purgeable *)
  1639.    IF colors <> NIL THEN
  1640.       BEGIN
  1641.          savedState := HGetState(Handle(colors));
  1642.          HNoPurge(Handle(colors));
  1643.       END;
  1644.    (* Calculate the number of bytes per row in the off-screen PixMap *)
  1645.    bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  1646.    (* Get the current QuickDraw version *)
  1647.    error := Gestalt(gestaltQuickdrawVersion, qdVersion);
  1648.    error := noErr;
  1649.    (* Make sure depth is indexed or depth is direct and 32-Bit QD installed *)
  1650.    IF (depth = 1) OR (depth = 2) OR (depth = 4) OR (depth = 8) OR
  1651.          (((depth = 16) OR (depth = 32)) AND (qdVersion >= gestalt32BitQD)) THEN
  1652.       BEGIN
  1653.          (* Maximum number of bytes per row is 16,382; make sure within range *)
  1654.          IF bytesPerRow <= kMaxRowBytes THEN
  1655.             BEGIN
  1656.                (* Make sure a color table is provided if the depth is indexed *)
  1657.                IF depth <= 8 THEN
  1658.                   IF colors = NIL THEN
  1659.                      (* Indexed depth and clut is NIL; is parameter error *)
  1660.                      error := paramErr;
  1661.             END
  1662.          ELSE
  1663.             (* # of bytes per row is more than 16,382; is parameter error *)
  1664.             error := paramErr;
  1665.       END
  1666.    ELSE
  1667.       (* Pixel depth isn’t valid; is parameter error *)
  1668.       error := paramErr;
  1669.    (* If sanity checks succeed, then allocate a new CGrafPort *)
  1670.    IF error = noErr THEN
  1671.       BEGIN
  1672.          newPort := CGrafPtr(NewPtr(SizeOf (CGrafPort)));
  1673.          IF newPort <> NIL THEN
  1674.             BEGIN
  1675.                (* Save the current port *)
  1676.                GetPort(savedPort);
  1677.                (* Initialize the new CGrafPort and make it the current port *)
  1678.                OpenCPort(newPort);
  1679.                (* Set portRect, visRgn, and clipRgn to the given bounds rect *)
  1680.                newPort^.portRect := bounds;
  1681.                RectRgn(newPort^.visRgn, bounds);
  1682.                ClipRect(bounds);
  1683.                (* Initialize the new PixMap for off-screen drawing *)
  1684.                error := SetUpPixMap(depth, bounds, colors, bytesPerRow,
  1685.                      newPort^.portPixMap);
  1686.                IF error = noErr THEN
  1687.                   BEGIN
  1688.                      (* Grab the initialized PixMap handle *)
  1689.                      newPixMap := newPort^.portPixMap;
  1690.                      (* Allocate and initialize a new GDevice *)
  1691.                      error := CreateGDevice(newPixMap, newDevice);
  1692.                   END;
  1693.                (* Restore the saved port *)
  1694.                SetPort(savedPort);
  1695.             END
  1696.          ELSE
  1697.             error := MemError;
  1698.       END;
  1699.    (* Restore the given state of the color table *)
  1700.    IF colors <> NIL THEN
  1701.       HSetState(Handle(colors), savedState);
  1702.    (* One Last Look Around The House Before We Go… *)
  1703.    IF error <> noErr THEN
  1704.       BEGIN
  1705.          (* Some error occurred; dispose of everything we allocated *)
  1706.          IF newPixMap <> NIL THEN
  1707.             BEGIN
  1708.                DisposCTable(newPixMap^^.pmTable);
  1709.                DisposPtr(newPixMap^^.baseAddr);
  1710.             END;
  1711.          IF newDevice <> NIL THEN
  1712.             BEGIN
  1713.                DisposHandle(Handle(newDevice^^.gdITable));
  1714.                DisposHandle(Handle(newDevice));
  1715.             END;
  1716.          IF newPort <> NIL THEN
  1717.             BEGIN
  1718.                CloseCPort(newPort);
  1719.                DisposPtr(Ptr(newPort));
  1720.             END;
  1721.       END
  1722.    ELSE
  1723.       BEGIN
  1724.          (* Everything’s OK; return refs to off-screen CGrafPort and GDevice *)
  1725.          retPort := newPort;
  1726.          retGDevice := newDevice;
  1727.       END;
  1728.    CreateOffScreen := error;
  1729. END;
  1730. MPW C Listing 1
  1731. #define kMaxRowBytes 0x3FFE /* Maximum number of bytes in a row of pixels */
  1732. OSErr CreateOffScreen(
  1733.     Rect       *bounds,     /* Bounding rectangle of off-screen */
  1734.     short      depth,       /* Desired number of bits per pixel in off-screen */
  1735.     CTabHandle colors,      /* Color table to assign to off-screen */
  1736.     CGrafPtr   *retPort,    /* Returns a pointer to the new CGrafPort */
  1737.     GDHandle   *retGDevice) /* Returns a handle to the new GDevice */
  1738. {
  1739.     CGrafPtr     newPort;     /* Pointer to the new off-screen CGrafPort */
  1740.     PixMapHandle newPixMap;   /* Handle to the new off-screen PixMap */
  1741.     GDHandle     newDevice;   /* Handle to the new off-screen GDevice */
  1742.     long         qdVersion;   /* Version of QuickDraw currently in use */
  1743.     GrafPtr      savedPort;   /* Pointer to GrafPort used for save/restore */
  1744.     SignedByte   savedState;  /* Saved state of color table handle */
  1745.     short        bytesPerRow; /* Number of bytes per row in the PixMap */
  1746.     OSErr        error;       /* Returns error code */
  1747.     /* Initialize a few things before we begin */
  1748.     newPort = nil;
  1749.     newPixMap = nil;
  1750.     newDevice = nil;
  1751.     error = noErr;
  1752.     /* Save the color table’s current state and make sure it isn’t purgeable */
  1753.     if (colors != nil)
  1754.     {
  1755.         savedState = HGetState( (Handle)colors );
  1756.         HNoPurge( (Handle)colors );
  1757.     }
  1758.     /* Calculate the number of bytes per row in the off-screen PixMap */
  1759.     bytesPerRow = ((depth * (bounds->right - bounds->left) + 31) >> 5) << 2;
  1760.     /* Get the current QuickDraw version */
  1761.     (void)Gestalt( gestaltQuickdrawVersion, &qdVersion );
  1762.     /* Make sure depth is indexed or depth is direct and 32-Bit QD installed */
  1763.     if (depth == 1 || depth == 2 || depth == 4 || depth == 8 ||
  1764.             ((depth == 16 || depth == 32) && qdVersion >= gestalt32BitQD))
  1765.     {
  1766.         /* Maximum number of bytes per row is 16,382; make sure within range */
  1767.         if (bytesPerRow <= kMaxRowBytes)
  1768.         {
  1769.             /* Make sure a color table is provided if the depth is indexed */
  1770.             if (depth <= 8)
  1771.                 if (colors == nil)
  1772.                   /* Indexed depth and clut is NIL; is parameter error */
  1773.                   error = paramErr;
  1774.         }
  1775.         else
  1776.             /* # of bytes per row is more than 16,382; is parameter error */
  1777.             error = paramErr;
  1778.     }
  1779.     else
  1780.         /* Pixel depth isn’t valid; is parameter error */
  1781.         error = paramErr;
  1782.     /* If sanity checks succeed, then allocate a new CGrafPort */
  1783.     if (error == noErr)
  1784.     {
  1785.         newPort = (CGrafPtr)NewPtr( sizeof (CGrafPort) );
  1786.         if (newPort != nil)
  1787.         {
  1788.             /* Save the current port */
  1789.             GetPort( &savedPort );
  1790.             /* Initialize the new CGrafPort and make it the current port */
  1791.             OpenCPort( newPort );
  1792.             /* Set portRect, visRgn, and clipRgn to the given bounds rect */
  1793.             newPort->portRect = *bounds;
  1794.             RectRgn( newPort->visRgn, bounds );
  1795.             ClipRect( bounds );
  1796.             /* Initialize the new PixMap for off-screen drawing */
  1797.             error = SetUpPixMap( depth, bounds, colors, bytesPerRow,
  1798.                     newPort->portPixMap );
  1799.             if (error == noErr)
  1800.             {
  1801.                 /* Grab the initialized PixMap handle */
  1802.                 newPixMap = newPort->portPixMap;
  1803.                 /* Allocate and initialize a new GDevice */
  1804.                 error = CreateGDevice( newPixMap, &newDevice );
  1805.             }
  1806.             /* Restore the saved port */
  1807.             SetPort( savedPort );
  1808.         }
  1809.         else
  1810.             error = MemError();
  1811.     }
  1812.     /* Restore the given state of the color table */
  1813.     if (colors != nil)
  1814.         HSetState( (Handle)colors, savedState );
  1815.     /* One Last Look Around The House Before We Go… */
  1816.     if (error != noErr)
  1817.     {
  1818.         /* Some error occurred; dispose of everything we allocated */
  1819.         if (newPixMap != nil)
  1820.         {
  1821.             DisposCTable( (**newPixMap).pmTable );
  1822.             DisposPtr( (**newPixMap).baseAddr );
  1823.         }
  1824.         if (newDevice != nil)
  1825.         {
  1826.             DisposHandle( (Handle)(**newDevice).gdITable );
  1827.             DisposHandle( (Handle)newDevice );
  1828.         }
  1829.         if (newPort != nil)
  1830.         {
  1831.             CloseCPort( newPort );
  1832.             DisposPtr( (Ptr)newPort );
  1833.         }
  1834.     }
  1835.     else
  1836.     {
  1837.         /* Everything’s OK; return refs to off-screen CGrafPort and GDevice */
  1838.         *retPort = newPort;
  1839.         *retGDevice = newDevice;
  1840.     }
  1841.     return error;
  1842. }
  1843. CreateOffScreen begins by making sure that the color table, if there is one, doesn’t get purged during the time that the off-screen graphics environment is created. Then, a sanity check is done for the given depth, bounds, and color table. The depth must be either 1, 2, 4, or 8 bits per pixel, or additionally 16 or 32 bits per pixel if 32-Bit QuickDraw is available. If these conditions aren’t satisfied, then it’s decided that there’s an error in the parameter list, and CreateOffScreen does nothing more. To determine whether 32-Bit QuickDraw is available or not, the _Gestalt routine is used. If _Gestalt returns a value that’s equal to or greater than the constant gestalt32BitQD, then 32-Bit QuickDraw is available and depths of 16 and 32 bits per pixel are supported. It’s not necessary to determine whether _Gestalt is available or not because it’s implemented as glue code in the Macintosh Programmer’s Workshop.
  1844. A check is then done to determine whether the number of bytes in each row of the off-screen pixel image is too much for QuickDraw to handle. Color QuickDraw can handle up to and including 16,382 ($3FFE) bytes in each row of any pixel image. If the required number of bytes per row exceeds this amount, then CreateOffScreen decides that there’s an error in the parameter list and does nothing more. The minimum number of bytes in a row that’s enough to cover the given boundary rectangle at the given pixel depth is calculated with the formula:
  1845.   bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  1846. This formula multiplies the number of pixels across the PixMap by the pixel depth to get the number of bits, and then this is divided by eight to get the number of bytes. This division by eight looks very strange because the number of bytes per row must be even, so this formula takes advantage of integer division and multiplication to make the result come out even. This particular formula additionally makes sure that the number of bytes per row is a multiple of four. This helps optimize the performance of Color QuickDraw operations because it allows Color QuickDraw to refer to each row beginning on a long word boundary in memory.
  1847. The last sanity check is to make sure that a color table is given as a parameter if it’s needed. Indexed-color graphics environments need color tables, so if the given pixel depth is eight or less (which implies an indexed-color graphics environment) and the given color table is NIL, then CreateOffScreen decides that there’s an error in the parameter list and does nothing more. If the given pixel depth is 16 or 32 (which implies a direct-color graphics environment), then CreateOffScreen ignores the given color table.
  1848. If all the sanity checks succeed, then the off-screen CGrafPort is allocated using a call to _NewPtr, and then it’s initialized and opened as a CGrafPort by passing the resulting pointer to _OpenCPort. Because _OpenCPort makes the new CGrafPort the current port, the current port is first saved so that it can be restored as the current port when CreateOffScreen is done.
  1849. As mentioned above, the _OpenCPort doesn’t necessarily initialize the portRect, visRgn, and clipRgn of the new CGrafPort to the areas that are needed for any particular off-screen graphics environment. So, the given boundary rectangle is assigned to the portRect field, _RectRgn is called to make the visRgn equal to the given boundary rectangle, and _ClipRect is called to set the clipRgn so that it’s equal to the given boundary rectangle.
  1850. The PixMap in the portPixMap field needs to be initialized for off-screen drawing, and that’s handled by the SetUpPixMap routine that’s described and defined in “Building the PixMap” later in this Note. Similarly, the off-screen GDevice must be created and initialized. That’s handled by the CreateGDevice routine that’s described and defined in “Building the GDevice” later in this Note.
  1851. Once these things are done, CreateOffScreen returns a pointer to the off-screen CGrafPort in the retPort parameter and a handle to the off-screen GDevice in the retGDevice parameter. The way to use these references is described in “Playing With Blocks”  later in this Note.
  1852. Building the PixMap
  1853. _OpenCPort initializes the portPixMap field of the CGrafPort it’s initializing with a copy of the PixMap of the current GDevice. When the CreateOffScreen routine described earlier executes, the current GDevice is unknown. So, all the fields of the PixMap that the new CGrafPort receives must be initialized so that it can be used for drawing off screen.* What follows is an overview of each of the PixMap fields and how they should be initialized for off-screen drawing.
  1854. baseAddr    pointer to the off-screen pixel image. The off-screen pixel image is allocated as a nonrelocatable block in the heap. The size of this block of memory is calculated from the rowBytes field, described next, multiplied by the number of rows in the given boundary rectangle.
  1855. rowBytes    number of bytes in each row of the pixel image. This value is calculated from the formula that’s given in the CreateOffScreen routine. The most significant bit of this field should be set so that Color QuickDraw knows that this is a PixMap rather than a BitMap. The maximum value, ignoring the most significant bit, is 16,382.
  1856. bounds    defines the coordinate system and the dimensions of the pixel image. For most off-screen drawing, this should be a rectangle that covers the entire off-screen graphics environment.
  1857. pmVersion    set of internally and externally defined flags. As of 32-Bit QuickDraw 1.2, only the baseAddr32 flag is defined externally. This flag is described in “Choosing Your Off-Screen Memory” later in this Note. For most off-screen drawing, this field is set to zero.
  1858. packType    image compression scheme for pictures. The options for this field are discussed in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 17-22 through 17-23. In this Note, image compression isn’t discussed so this field is set to zero.
  1859. packSize    internally used field. This field is always set to zero.
  1860. hRes    horizontal resolution of the pixel map. By default, the QuickDraw resolution is 72 dots per inch,which is the value this Note uses. This is a fixed-point field, so the actual value in this field is $00480000.
  1861. vRes    vertical resolution of the pixel map. See the hRes description.
  1862. pixelType    format of the pixels. In indexed-color pixel maps, this field holds zero. In direct-color pixel maps, this field holds the RGBDirect constant, which is equal to 16.
  1863. pixelSize    number of bits in every pixel. For indexed-color pixels, this is 1, 2, 4, or 8 bits per pixel. For direct-color pixels, this is 16 or 32 bits per pixel.
  1864. cmpCount    number of components in every pixel. In indexed-color pixel maps, this field is set to 1. In direct-color pixel maps, this field is set to 3. Sometimes it’s handy to set this field to 4 in 32-bit deep pixel maps when they’re being saved in a picture. See the “Color QuickDraw” chapter of Inside Macintosh Volume VI, page 17-23, for details about this.
  1865. cmpSize    number of bits in each color component. In indexed-color pixel maps, this field is set to the same value that’s in the pixelSize field. In 16-bit deep direct pixel maps, this field is set to 5. In 32-bit deep direct pixel maps, this field is set to 8.
  1866. planeBytes    not currently defined. This field is set to zero.
  1867. pmTable    handle to the color table for indexed-color pixel maps. A method to create a color table is given in “About That Creation Thing . . .” later in this Note. In direct-color pixel maps, this field contains a handle to a dummy color table, and building one of these is shown in the SetUpPixMap routine in Listing 2.
  1868. pmReserved    not currently defined. This field is set to zero.
  1869. (*This part of these routines really bothers me because it feels impure to initialize all the PixMap fields when _OpenCPort has initialized them already, just not in a way that’s any good for off-screen drawing. I tried creating the GDevice and PixMap first and then calling _OpenCPort so that it initializes its PixMap for off-screen drawing, but then you end up with two pixel maps and that makes this tougher to explain, or you have to dispose of one PixMap which seems worse than the method I’m using.)
  1870. The SetUpPixMap routine in Listing 2 initializes the PixMap that’s passed to it in the aPixMap parameter so that it can be used in an off-screen graphics environment. The depth, bounds, and color parameters are the same as the ones passed to the CreateOffScreen routine. The bytesPerRow parameter is the number of bytes in each row of the off-screen pixel image. A description of SetUpPixMap follows the listing.
  1871. MPW Pascal Listing 2
  1872. FUNCTION SetUpPixMap(
  1873.    depth:       Integer;     {Desired number of bits/pixel in off-screen}
  1874.    bound:       Rect;        {Bounding rectangle of off-screen}
  1875.    colors:      CTabHandle;  {Color table to assign to off-screen}
  1876.    bytesPerRow: Integer;     {Number of bytes in each row of pixels}
  1877.    aPixMap:     PixMapHandle {Handle to the PixMap being initialized}
  1878.    ): OSErr;
  1879.    CONST
  1880.       kDefaultRes = $00480000; {Default resolution is 72 DPI; Fixed type}
  1881.    VAR
  1882.       newColors:   CTabHandle; {Color table used for the off-screen PixMap}
  1883.       offBaseAddr: Ptr;        {Pointer to the off-screen pixel image}
  1884.       error:       OSErr;      {Returns error code}
  1885. BEGIN
  1886.    error := noErr;
  1887.    newColors := NIL;
  1888.     offBaseAddr := NIL;
  1889.    (* Clone the clut if indexed color; allocate a dummy clut if direct color *)
  1890.    IF depth <= 8 THEN
  1891.       BEGIN
  1892.          newColors := colors;
  1893.          error := HandToHand(Handle(newColors));
  1894.       END
  1895.    ELSE
  1896.       BEGIN
  1897.          newColors := CTabHandle(NewHandle(SizeOf(ColorTable) -
  1898.                SizeOf(CSpecArray)));
  1899.          error := MemError;
  1900.       END;
  1901.    IF error = noErr THEN
  1902.       BEGIN
  1903.          (* Allocate pixel image; long integer multiplication avoids overflow *)
  1904.          offBaseAddr := NewPtr(LongInt(bytesPerRow) * (bound.bottom -
  1905.                bound.top));
  1906.          IF offBaseAddr <> NIL THEN
  1907.             WITH aPixMap^^ DO
  1908.                BEGIN
  1909.                   (* Initialize fields common to indexed and direct PixMaps *)
  1910.                   baseAddr := offBaseAddr;     {Point to image}
  1911.                   rowBytes := BOR(bytesPerRow, {MSB set for PixMap}
  1912.                         $8000);
  1913.                   bounds := bound;             {Use given bounds}
  1914.                   pmVersion := 0;              {No special stuff}
  1915.                   packType := 0;               {Default PICT pack}
  1916.                   packSize := 0;               {Always zero when in memory}
  1917.                   hRes := kDefaultRes;         {72 DPI default resolution}
  1918.                   vRes := kDefaultRes;         {72 DPI default resolution}
  1919.                   pixelSize := depth;          {Set number of bits/pixel}
  1920.                   planeBytes := 0;             {Not used}
  1921.                   pmReserved := 0;             {Not used}
  1922.                   (* Initialize fields specific to indexed and direct PixMaps *)
  1923.                   IF depth <= 8 THEN
  1924.                      BEGIN
  1925.                         (* PixMap is indexed *)
  1926.                         pixelType := 0;       {Indicates indexed}
  1927.                         cmpCount := 1;        {Have 1 component}
  1928.                         cmpSize := depth;     {Component size=depth}
  1929.                         pmTable := newColors; {Handle to CLUT}
  1930.                      END
  1931.                   ELSE
  1932.                      BEGIN
  1933.                         (* PixMap is direct *)
  1934.                         pixelType := RGBDirect; {Indicates direct}
  1935.                         cmpCount := 3;          {Have 3 components}
  1936.                         IF depth = 16 THEN
  1937.                            cmpSize := 5         {5 bits/component}
  1938.                         ELSE
  1939.                            cmpSize := 8;        {8 bits/component}
  1940.                         (* Initialize fields of the dummy color table *)
  1941.                         newColors^^.ctSeed := 3 * aPixMap^^.cmpSize;
  1942.                         newColors^^.ctFlags := 0;
  1943.                         newColors^^.ctSize := 0;
  1944.                         pmTable := newColors;
  1945.                      END;
  1946.                END
  1947.          ELSE
  1948.             error := MemError;
  1949.       END
  1950.    ELSE
  1951.       newColors := NIL;
  1952.    (* If no errors occurred, return a handle to the new off-screen PixMap *)
  1953.    IF error <> noErr THEN
  1954.       BEGIN
  1955.          IF newColors <> NIL THEN
  1956.             DisposCTable(newColors);
  1957.       END;
  1958.     (* Return the error code *)
  1959.     SetUpPixMap := error;
  1960. END;
  1961. MPW C Listing 2
  1962. #define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */
  1963. OSErr SetUpPixMap(
  1964.     short        depth,       /* Desired number of bits/pixel in off-screen */
  1965.     Rect         *bounds,     /* Bounding rectangle of off-screen */
  1966.     CTabHandle   colors,      /* Color table to assign to off-screen */
  1967.     short        bytesPerRow, /* Number of bytes per row in the PixMap */
  1968.     PixMapHandle aPixMap)     /* Handle to the PixMap being initialized */
  1969. {
  1970.     CTabHandle newColors;   /* Color table used for the off-screen PixMap */
  1971.     Ptr        offBaseAddr; /* Pointer to the off-screen pixel image */
  1972.     OSErr      error;       /* Returns error code */
  1973.     error = noErr;
  1974.     newColors = nil;
  1975.     offBaseAddr = nil;
  1976.     /* Clone the clut if indexed color; allocate a dummy clut if direct color */
  1977.     if (depth <= 8)
  1978.     {
  1979.         newColors = colors;
  1980.         error = HandToHand( (Handle *)&newColors );
  1981.     }
  1982.     else
  1983.     {
  1984.         newColors = (CTabHandle)NewHandle( sizeof (ColorTable) -
  1985.                 sizeof (CSpecArray) );
  1986.         error = MemError();
  1987.     }
  1988.     if (error == noErr)
  1989.     {
  1990.         /* Allocate pixel image; long integer multiplication avoids overflow */
  1991.         offBaseAddr = NewPtr( (unsigned long)bytesPerRow * (bounds->bottom -
  1992.                 bounds->top) );
  1993.         if (offBaseAddr != nil)
  1994.         {
  1995.             /* Initialize fields common to indexed and direct PixMaps */
  1996.             (**aPixMap).baseAddr = offBaseAddr;  /* Point to image */
  1997.             (**aPixMap).rowBytes = bytesPerRow | /* MSB set for PixMap */
  1998.                     0x8000;
  1999.             (**aPixMap).bounds = *bounds;        /* Use given bounds */
  2000.             (**aPixMap).pmVersion = 0;           /* No special stuff */
  2001.             (**aPixMap).packType = 0;            /* Default PICT pack */
  2002.             (**aPixMap).packSize = 0;            /* Always zero in mem */
  2003.             (**aPixMap).hRes = kDefaultRes;      /* 72 DPI default res */
  2004.             (**aPixMap).vRes = kDefaultRes;      /* 72 DPI default res */
  2005.             (**aPixMap).pixelSize = depth;       /* Set # bits/pixel */
  2006.             (**aPixMap).planeBytes = 0;          /* Not used */
  2007.             (**aPixMap).pmReserved = 0;          /* Not used */
  2008.             /* Initialize fields specific to indexed and direct PixMaps */
  2009.             if (depth <= 8)
  2010.             {
  2011.                 /* PixMap is indexed */
  2012.                 (**aPixMap).pixelType = 0;       /* Indicates indexed */
  2013.                 (**aPixMap).cmpCount = 1;        /* Have 1 component */
  2014.                 (**aPixMap).cmpSize = depth;     /* Component size=depth */
  2015.                 (**aPixMap).pmTable = newColors; /* Handle to CLUT */
  2016.             }
  2017.             else
  2018.             {
  2019.                 /* PixMap is direct */
  2020.                 (**aPixMap).pixelType = RGBDirect; /* Indicates direct */
  2021.                 (**aPixMap).cmpCount = 3;          /* Have 3 components */
  2022.                 if (depth == 16)
  2023.                     (**aPixMap).cmpSize = 5;       /* 5 bits/component */
  2024.                 else
  2025.                     (**aPixMap).cmpSize = 8;       /* 8 bits/component */
  2026.                 (**newColors).ctSeed = 3 * (**aPixMap).cmpSize;
  2027.                 (**newColors).ctFlags = 0;
  2028.                 (**newColors).ctSize = 0;
  2029.                 (**aPixMap).pmTable = newColors;
  2030.             }
  2031.         }
  2032.         else
  2033.             error = MemError();
  2034.     }
  2035.     else
  2036.         newColors = nil;
  2037.     /* If no errors occurred, return a handle to the new off-screen PixMap */
  2038.     if (error != noErr)
  2039.     {
  2040.         if (newColors != nil)
  2041.             DisposCTable( newColors );
  2042.     }
  2043.     /* Return the error code */
  2044.     return error;
  2045. }
  2046. SetUpPixMap begins by copying the given color table if an indexed-color graphics environment is being built, or allocating a dummy color table if a direct-color graphics environment is being built. A copy of the color table is made because this allows the given color table and the off-screen graphics environment’s color table to be manipulated independently without interfering with each other, and this lets the off-screen graphics environment routines manipulate the color table without needing to worry about whether the color table is a 'clut' resource or not. The dummy color table is made so that routines which assume that every PixMap has a color table won’t do something catastrophic if they find a NIL color table. The off-screen pixel image is then allocated as a nonrelocatable block in the application’s heap.
  2047. Some of the fields of a PixMap have to be initialized differently depending upon whether the indexed-color model or the direct-color model is being used. So, the fields that are the same regardless of the color model that’s being used are assigned first. Then the desired pixel depth is compared to 8. If the depth is less than or equal to 8, then the rest of the fields are initialized for the indexed-color model. Otherwise, the rest of the fields are initialized for the direct color model. In the case of the direct-color model, the dummy color table is initialized to have no CSpecArray entries and its ctSeed field is set to three times the component size. This dummy color table is then installed into the PixMap.
  2048. Once SetUpPixMap completes, the PixMap of the new CGrafPort is ready to hold an off-screen image. It’s not quite ready to be drawn into with Color QuickDraw though. To do that, the off-screen GDevice is still needed; the construction and initialization of the GDevice are covered in the next section.
  2049. Building the GDevice
  2050. The _OpenCPort routine automatically allocates and initializes a PixMap, and the SetUpPixMap routine reinitializes that existing PixMap. _OpenCPort doesn’t allocate nor initialize a GDevice, so one has to be created from scratch. Pages 21-20 through 21-21 of “The Graphics Devices Manager” chapter of Inside Macintosh Volume VI describe the _NewGDevice routine. This routine seems as though it’s the ticket to getting a GDevice for off-screen drawing, but it always allocates the new GDevice in the system heap. That’s not so good because if your program unexpectedly quits or if you just forget to dispose of the GDevice before you quit for real, the GDevice gets orphaned in the system heap. To prevent this from happening, _NewGDevice should be ignored and the off-screen GDevice should instead be allocated and initialized from scratch. What follows is a description of how each field of the GDevice structure should be initialized.
  2051. gdRefNum    reference number of video driver. Off-screen graphics environments don’t need to have video drivers because there’s no video device associated with them, so this field is set to zero.
  2052. gdID    used to identify specific GDevice structures from color-search procedures. This isn’t necessary for off-screen drawing, so this is normally set to zero.
  2053. gdType    type of GDevice. This field is set to the constant clutType (equal to zero) for an indexed-color environment and set to the constant directType (equal to 2) for a direct-color environment.
  2054. gdITable    handle to the inverse table. Initially, this field is set to an arbitrarily small handle. Later, the _MakeITable routine is used to resize and initialize this handle to a real inverse table.
  2055. gdResPref    inverse-table resolution. When _MakeITable is called by QuickDraw, the value of this field is used as the inverse-table resolution. Almost all inverse tables have a resolution of 4. There are some cases when a inverse-table resolution of 5 is useful, particularly when the arithmetic transfer modes are used with _CopyBits. See “The GDevice” earlier in this Note.
  2056. gdSearchProc    pointer to the color-search procedure. If a color-search procedure is needed, this field can be set later by calling the _AddSearch routine (see the “Color Manager” chapter of Inside Macintosh Volume V, pages 145 through 147). Usually, this field is just set to NIL and left at that.
  2057. gdCompProc    pointer to the color-complement procedure. If a color-complement procedure is needed, this field can be set later by calling the _AddComp routine (see the “Color Manager” chapter of Inside Macintosh Volume V, pages 145 through 147). Usually, this field is set to NIL and left at that.
  2058. gdFlags    flags indicating certain states of the GDevice. This field should initially be set to zeroes. After the GDevice has been built, these flags can be set with the _SetDeviceAttrs routine (see the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI, pages 21-10 and 21-22).
  2059. gdPMap    handle to a PixMap. A handle to the PixMap of the CGrafPort that was created earlier is put into this field.
  2060. gdRefCon    miscellaneous data. _CalcCMask and _SeedCFill use this field as described on pages 71 through 72 of Inside Macintosh Volume V. Initially, this field is set to zero.
  2061. gdNextGD    handle to next GDevice in the GDevice list. The system maintains a linked list of GDevice records in which there’s one GDevice for every screen, and the links are kept in this field. Off-screen GDevice structures should never be put into this list, so this field should be set to NIL.
  2062. gdRect    rectangle of GDevice. Strictly speaking, this field is used only for screens, but it should be the same as the bounds rectangle of the off-screen PixMap.
  2063. gdMode    current video mode. This field is used by video drivers to keep track of the current mode that the video device is in. For off-screen GDevice structures, this field should be set to -1.
  2064. gdCC…    These four fields are used only with GDevice structures for screens. For off-screen GDevice structures, these fields should be set to zero.
  2065. gdReserved    not currently defined. This field is set to zero.
  2066. The CreateGDevice routine shown below in Listing 3 allocates and initializes a GDevice structure. It takes the initialized off-screen PixMap in the basePixMap parameter and returns the initialized GDevice in the retGDevice parameter. If any error occurs, any memory that’s allocated is disposed of and the result code is returned as a function result.
  2067. MPW Pascal Listing 3
  2068. FUNCTION CreateGDevice(
  2069.    basePixMap:     PixMapHandle; {Handle to the PixMap to base GDevice on}
  2070.    VAR retGDevice: GDHandle      {Returns a handle to the new GDevice}
  2071.    ): OSErr;
  2072.    CONST
  2073.       kITabRes = 4; {Inverse-table resolution}
  2074.    VAR
  2075.       newDevice:  GDHandle;   {Handle to the new GDevice}
  2076.       embryoITab: ITabHandle; {Handle to the embryonic inverse table}
  2077.       error:      OSErr;      {Error code}
  2078. BEGIN
  2079.    (* Initialize a few things before we begin *)
  2080.    error := noErr;
  2081.    newDevice := NIL;
  2082.    embryoITab := NIL;
  2083.    (* Allocate memory for the new GDevice *)
  2084.    newDevice := GDHandle(NewHandle(SizeOf(GDevice)));
  2085.    IF newDevice <> NIL THEN
  2086.       BEGIN
  2087.          (* Allocate the embryonic inverse table *)
  2088.          embryoITab := ITabHandle(NewHandleClear(2));
  2089.          IF embryoITab <> NIL THEN
  2090.             BEGIN
  2091.                (* Initialize the new GDevice fields *)
  2092.                WITH newDevice^^ DO
  2093.                   BEGIN
  2094.                      gdRefNum := 0;                 {Only used for screens}
  2095.                      gdID := 0;                     {Won’t normally use}
  2096.                      IF basePixMap^^.pixelSize <= 8 THEN
  2097.                         gdType := clutType          {Depth≤8; clut device}
  2098.                      ELSE
  2099.                         gdType := directType;       {Depth>8; direct device}
  2100.                      gdITable := embryoITab;        {2-byte handle for now}
  2101.                      gdResPref := kITabRes;         {Normal inv table res}
  2102.                      gdSearchProc := NIL;           {No color-search proc}
  2103.                      gdCompProc := NIL;             {No complement proc}
  2104.                      gdFlags := 0;                  {Will set these later}
  2105.                      gdPMap := basePixMap;          {Reference our PixMap}
  2106.                      gdRefCon := 0;                 {Won’t normally use}
  2107.                      gdNextGD := NIL;               {Not in GDevice list}
  2108.                      gdRect := basePixMap^^.bounds; {Use PixMap dimensions}
  2109.                      gdMode := -1;                  {For nonscreens}
  2110.                      gdCCBytes := 0;                {Only used for screens}
  2111.                      gdCCDepth := 0;                {Only used for screens}
  2112.                      gdCCXData := NIL;              {Only used for screens}
  2113.                      gdCCXMask := NIL;              {Only used for screens}
  2114.                      gdReserved := 0;               {Currently unused}
  2115.                   END;
  2116.                (* Set color-device bit if PixMap isn’t black & white *)
  2117.                IF basePixMap^^.pixelSize > 1 THEN
  2118.                   SetDeviceAttribute(newDevice, gdDevType, true);
  2119.                (* Set bit to indicate that the GDevice has no video driver *)
  2120.                SetDeviceAttribute(newDevice, noDriver, true);
  2121.                (* Initialize the inverse table *)
  2122.                IF basePixMap^^.pixelSize <= 8 THEN
  2123.                   BEGIN
  2124.                      MakeITable(basePixMap^^.pmTable, newDevice^^.gdITable,
  2125.                            newDevice^^.gdResPref);
  2126.                      error := QDError;
  2127.                   END;
  2128.             END
  2129.          ELSE
  2130.             error := MemError;
  2131.       END
  2132.    ELSE
  2133.       error := MemError;
  2134.    (* Handle any errors along the way *)
  2135.    IF error <> noErr THEN
  2136.       BEGIN
  2137.          IF embryoITab <> NIL THEN
  2138.             DisposHandle(Handle(embryoITab));
  2139.          IF newDevice <> NIL THEN
  2140.             DisposHandle(Handle(newDevice));
  2141.       END
  2142.    ELSE
  2143.       retGDevice := newDevice;
  2144.    (* Return a handle to the new GDevice *)
  2145.    CreateGDevice := error;
  2146. END;
  2147. MPW C Listing 3
  2148. #define kITabRes 4 /* Inverse-table resolution */
  2149. OSErr CreateGDevice(
  2150.     PixMapHandle basePixMap,  /* Handle to the PixMap to base GDevice on */
  2151.     GDHandle     *retGDevice) /* Returns a handle to the new GDevice */
  2152. {
  2153.     GDHandle   newDevice;  /* Handle to the new GDevice */
  2154.     ITabHandle embryoITab; /* Handle to the embryonic inverse table */
  2155.     Rect       deviceRect; /* Rectangle of GDevice */
  2156.     OSErr      error;      /* Error code */
  2157.     /* Initialize a few things before we begin */
  2158.     error = noErr;
  2159.     newDevice = nil;
  2160.     embryoITab = nil;
  2161.     /* Allocate memory for the new GDevice */
  2162.     newDevice = (GDHandle)NewHandle( sizeof (GDevice) );
  2163.     if (newDevice != nil)
  2164.     {
  2165.         /* Allocate the embryonic inverse table */
  2166.         embryoITab = (ITabHandle)NewHandleClear( 2 );
  2167.         if (embryoITab != nil)
  2168.         {
  2169.             /* Set rectangle of device to PixMap bounds */
  2170.             deviceRect = (**basePixMap).bounds;
  2171.             /* Initialize the new GDevice fields */
  2172.             (**newDevice).gdRefNum = 0;            /* Only used for screens */
  2173.             (**newDevice).gdID = 0;                /* Won’t normally use */
  2174.             if ((**basePixMap).pixelSize <= 8)
  2175.                 (**newDevice).gdType = clutType;   /* Depth≤8; clut device */
  2176.             else
  2177.                 (**newDevice).gdType = directType; /* Depth>8; direct device */
  2178.             (**newDevice).gdITable = embryoITab;   /* 2-byte handle for now */
  2179.             (**newDevice).gdResPref = kITabRes;    /* Normal inv table res */
  2180.             (**newDevice).gdSearchProc = nil;      /* No color-search proc */
  2181.             (**newDevice).gdCompProc = nil;        /* No complement proc */
  2182.             (**newDevice).gdFlags = 0;             /* Will set these later */
  2183.             (**newDevice).gdPMap = basePixMap;     /* Reference our PixMap */
  2184.             (**newDevice).gdRefCon = 0;            /* Won’t normally use */
  2185.             (**newDevice).gdNextGD = nil;          /* Not in GDevice list */
  2186.             (**newDevice).gdRect = deviceRect;     /* Use PixMap dimensions */
  2187.             (**newDevice).gdMode = -1;             /* For nonscreens */
  2188.             (**newDevice).gdCCBytes = 0;           /* Only used for screens */
  2189.             (**newDevice).gdCCDepth = 0;           /* Only used for screens */
  2190.             (**newDevice).gdCCXData = 0;           /* Only used for screens */
  2191.             (**newDevice).gdCCXMask = 0;           /* Only used for screens */
  2192.             (**newDevice).gdReserved = 0;          /* Currently unused */
  2193.             /* Set color-device bit if PixMap isn’t black & white */
  2194.             if ((**basePixMap).pixelSize > 1)
  2195.                 SetDeviceAttribute( newDevice, gdDevType, true );
  2196.             /* Set bit to indicate that the GDevice has no video driver */
  2197.             SetDeviceAttribute( newDevice, noDriver, true );
  2198.             /* Initialize the inverse table */
  2199.             if ((**basePixMap).pixelSize <= 8)
  2200.             {
  2201.                 MakeITable( (**basePixMap).pmTable, (**newDevice).gdITable,
  2202.                         (**newDevice).gdResPref );
  2203.                 error = QDError();
  2204.             }
  2205.         }
  2206.         else
  2207.             error = MemError();
  2208.     }
  2209.     else
  2210.         error = MemError();
  2211.     /* Handle any errors along the way */
  2212.     if (error != noErr)
  2213.     {
  2214.         if (embryoITab != nil)
  2215.             DisposHandle( (Handle)embryoITab );
  2216.         if (newDevice != nil)
  2217.             DisposHandle( (Handle)newDevice );
  2218.     }
  2219.     else
  2220.         *retGDevice = newDevice;
  2221.     /* Return a handle to the new GDevice */
  2222.     return error;
  2223. }
  2224. CreateGDevice begins by allocating the GDevice structure and an embryonic form of the inverse table in the current heap. The inverse table is allocated as two zero bytes for now; it’ll be resized and initialized to be a real inverse table later in this routine. Then, each of the GDevice fields are initialized as described earlier.
  2225. After all the fields have been initialized, the gdFlags field is set through _SetDeviceAttribute. If the desired pixel depth is greater than 1, then the gdDevType bit is set. This indicates that the GDevice is for a color graphics environment. This bit should be set even if a gray-scale color table is used for this off-screen graphics environment. The noDriver bit is set because this is an off-screen GDevice and so there’s no associated video device driver.
  2226. Finally, the inverse table is resized and initialized by calling the _MakeITable routine. A handle to the two-byte embryonic inverse table that was created earlier in CreateGDevice is passed as a parameter, as is a handle to the off-screen color table and the preferred inverse-table resolution.
  2227. All Fall Down
  2228. Now that we have a way to create an off-screen graphics environment, there has to be a way to get rid of it too. The DisposeOffScreen routine shown in Listing 4 does this. The CreateOffScreen routine returns an off-screen graphics environment that’s represented by a CGrafPort and GDevice. The DisposeOffScreen routine takes the off-screen CGrafPort and GDevice and deallocates all the memory that’s associated with them including the CGrafPort and its dependent structures, the GDevice, the PixMap, the color table, and the inverse table.
  2229. MPW Pascal Listing 4
  2230. PROCEDURE DisposeOffScreen(
  2231.    doomedPort:    CGrafPtr; {Pointer to the CGrafPort we’re getting rid of}
  2232.    doomedGDevice: GDHandle  {Handle to the GDevice we’re getting rid of}
  2233.    );
  2234.    VAR
  2235.       currPort:    CGrafPtr; {Pointer to the current port}
  2236.       currGDevice: GDHandle; {Handle to the current GDevice}
  2237. BEGIN
  2238.    (* Check to see whether the doomed CGrafPort is the current port *)
  2239.    GetPort(GrafPtr(currPort));
  2240.    IF currPort = doomedPort THEN
  2241.       BEGIN
  2242.          (* It is; set current port to Window Manager CGrafPort *)
  2243.          GetCWMgrPort(currPort);
  2244.          SetPort(GrafPtr(currPort));
  2245.       END;
  2246.    (* Check to see whether the doomed GDevice is the current GDevice *)
  2247.    currGDevice := GetGDevice;
  2248.    IF currGDevice = doomedGDevice THEN
  2249.       (* It is; set current GDevice to the main screen’s GDevice *)
  2250.       SetGDevice(GetMainDevice);
  2251.    (* Throw everything away *)
  2252.    doomedGDevice^^.gdPMap := NIL;
  2253.    DisposGDevice(doomedGDevice);
  2254.    DisposPtr(doomedPort^.portPixMap^^.baseAddr);
  2255.    IF doomedPort^.portPixMap^^.pmTable <> NIL THEN
  2256.       DisposCTable(doomedPort^.portPixMap^^.pmTable);
  2257.    CloseCPort(doomedPort);
  2258.    DisposPtr(Ptr(doomedPort));
  2259. END;
  2260. MPW C Listing 4
  2261. void DisposeOffScreen(
  2262.     CGrafPtr doomedPort,    /* Pointer to the CGrafPort to be disposed of */
  2263.     GDHandle doomedGDevice) /* Handle to the GDevice to be disposed of */
  2264. {
  2265.     CGrafPtr currPort;    /* Pointer to the current port */
  2266.     GDHandle currGDevice; /* Handle to the current GDevice */
  2267.     /* Check to see whether the doomed CGrafPort is the current port */
  2268.     GetPort( (GrafPtr *)&currPort );
  2269.     if (currPort == doomedPort)
  2270.     {
  2271.         /* It is; set current port to Window Manager CGrafPort */
  2272.         GetCWMgrPort( &currPort );
  2273.         SetPort( (GrafPtr)currPort );
  2274.     }
  2275.     /* Check to see whether the doomed GDevice is the current GDevice */
  2276.     currGDevice = GetGDevice();
  2277.     if (currGDevice == doomedGDevice)
  2278.         /* It is; set current GDevice to the main screen’s GDevice */
  2279.         SetGDevice( GetMainDevice() );
  2280.     /* Throw everything away */
  2281.     (**doomedGDevice).gdPMap = nil;
  2282.     DisposGDevice( doomedGDevice );
  2283.     DisposPtr( (**doomedPort->portPixMap).baseAddr );
  2284.     if ((**doomedPort->portPixMap).pmTable != nil)
  2285.         DisposCTable( (**doomedPort->portPixMap).pmTable );
  2286.     CloseCPort( doomedPort );
  2287.     DisposPtr( (Ptr)doomedPort );
  2288. }
  2289. One mildly tricky aspect of this is that we shouldn’t dispose of the current graphics environment. To prevent this, the current port is retrieved by a call to _GetPort. If it returns a pointer to the same port that DisposeOffScreen is disposing, then the current port is set to the Window Manager’s CGrafPort. That was an arbitrary choice, but it’s the most neutral. Similarly, the current GDevice is retrieved by a call to _GetGDevice. If it returns a handle to the same GDevice that DisposeOffScreen is disposing, then the current port is set to the main screen’s GDevice. Again, that’s an arbitrary, neutral choice.
  2290. The inverse table, GDevice, pixel image, and color table are disposed of. Before disposing of the color table, a check is first made to see whether it’s NIL. That’s because it’s reasonable, though not normal, for the PixMap not to have even a dummy color table if the direct-color model is being used. Then the CGrafPort is closed which deallocates all the pieces associated with the CGrafPort, including the PixMap. Once this is done, all the structures that were created by calling CreateOffScreen are deallocated.
  2291. Playing With Blocks
  2292. Now that these four routines with two entry points can create and dispose of off-screen graphics environments, how are they used? There are several phases to using an off-screen graphics environment: creating it, drawing into it, switching between it and other off-screen and on-screen graphics environments, copying images to and from it, and disposing of it. Listing 5 shows a routine called ExerciseOffScreen which is a very basic example of all of these phases.
  2293. MPW Pascal Listing 5
  2294. PROCEDURE ExerciseOffScreen;
  2295.    CONST
  2296.       kOffDepth  = 8;    {Number of bits per pixel in off-screen environment}
  2297.       rGrayClut  = 1600; {Resource ID of gray-scale clut}
  2298.       rColorClut = 1601; {Resource ID of full-color clut}
  2299.    VAR
  2300.       grayPort:    CGrafPtr;   {Graphics environment for gray off screen}
  2301.       grayDevice:  GDHandle;   {Color environment for gray off screen}
  2302.       colorPort:   CGrafPtr;   {Graphics environment for color off screen}
  2303.       colorDevice: GDHandle;   {Color environment for color off screen}
  2304.       savedPort:   GrafPtr;    {Pointer to the saved graphics environment}
  2305.       savedDevice: GDHandle;   {Handle to the saved color environment}
  2306.       offColors:   CTabHandle; {Colors for off-screen environments}
  2307.       offRect:     Rect;       {Rectangle of off-screen environments}
  2308.       circleRect:  Rect;       {Rectangles for circle-drawing}
  2309.       count:       Integer;    {Generic counter}
  2310.       aColor:      RGBColor;   {Color used for drawing off screen}
  2311.       error:       OSErr;      {Error return from off-screen creation}
  2312. BEGIN
  2313.    (* Set up the rectangle for the off-screen graphics environments *)
  2314.    SetRect(offRect, 0, 0, 256, 256);
  2315.    (* Get the color table for the gray off-screen graphics environment *)
  2316.    offColors := GetCTable(rGrayClut);
  2317.    (* Create the gray off-screen graphics environment *)
  2318.    error := CreateOffScreen(offRect, kOffDepth, offColors, grayPort,
  2319.          grayDevice);
  2320.    IF error = noErr THEN
  2321.       BEGIN
  2322.          (* Get the color table for the color off-screen graphics environment *)
  2323.          offColors := GetCTable(rColorClut);
  2324.          (* Create the color off-screen graphics environment *)
  2325.          error := CreateOffScreen(offRect, kOffDepth, offColors, colorPort,
  2326.                colorDevice);
  2327.          IF error = noErr THEN
  2328.             BEGIN
  2329.                (* Save the current graphics environment *)
  2330.                GetPort(savedPort);
  2331.                savedDevice := GetGDevice;
  2332.                (* Set the current graphics environment to the gray one *)
  2333.                SetPort(GrafPtr(grayPort));
  2334.                SetGDevice(grayDevice);
  2335.                (* Draw gray-scale ramp into the gray off-screen environment *)
  2336.                FOR count := 0 TO 255 DO
  2337.                   BEGIN
  2338.                      aColor.red := count * 257;
  2339.                      aColor.green := aColor.red;
  2340.                      aColor.blue := aColor.green;
  2341.                      RGBForeColor(aColor);
  2342.                      MoveTo(0, count);
  2343.                      LineTo(255, count);
  2344.                   END;
  2345.                (* Copy gray ramp into color off-screen colorized with green *)
  2346.                SetPort(GrafPtr(colorPort));
  2347.                SetGDevice(colorDevice);
  2348.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  2349.                RGBForeColor(aColor);
  2350.                CopyBits(GrafPtr(grayPort)^.portBits,
  2351.                      GrafPtr(colorPort)^.portBits,
  2352.                      grayPort^.portRect,
  2353.                      colorPort^.portRect,
  2354.                      srcCopy + ditherCopy, NIL);
  2355.                (* Draw red, green, and blue circles *)
  2356.                PenSize(8, 8);
  2357.                aColor.red := $FFFF; aColor.green := $0000; aColor.blue := $0000;
  2358.                RGBForeColor(aColor);
  2359.                circleRect := colorPort^.portRect;
  2360.                FrameOval(circleRect);
  2361.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  2362.                RGBForeColor(aColor);
  2363.                InsetRect(circleRect, 20, 20);
  2364.                FrameOval(circleRect);
  2365.                aColor.red := $0000; aColor.green := $0000; aColor.blue := $FFFF;
  2366.                RGBForeColor(aColor);
  2367.                InsetRect(circleRect, 20, 20);
  2368.                FrameOval(circleRect);
  2369.                (* Copy the color off-screen environment to the current port *)
  2370.                SetPort(savedPort);
  2371.                SetGDevice(savedDevice);
  2372.                CopyBits(GrafPtr(colorPort)^.portBits, savedPort^.portBits,
  2373.                      colorPort^.portRect, savedPort^.portRect,
  2374.                      srcCopy, NIL);
  2375.                (* Dispose of the off-screen graphics environments *)
  2376.                DisposeOffScreen(grayPort, grayDevice);
  2377.                DisposeOffScreen(colorPort, colorDevice);
  2378.             END;
  2379.       END;
  2380. END;
  2381. MPW C Listing 5
  2382. #define kOffDepth  8    /* Number of bits per pixel in off-screen environment */
  2383. #define rGrayClut  1600 /* Resource ID of gray-scale clut */
  2384. #define rColorClut 1601 /* Resource ID of full-color clut */
  2385. void ExerciseOffScreen()
  2386. {
  2387.     CGrafPtr   grayPort;    /* Graphics environment for gray off screen */
  2388.     GDHandle   grayDevice;  /* Color environment for gray off screen */
  2389.     CGrafPtr   colorPort;   /* Graphics environment for color off screen */
  2390.     GDHandle   colorDevice; /* Color environment for color off screen */
  2391.     GrafPtr    savedPort;   /* Pointer to the saved graphics environment */
  2392.     GDHandle   savedDevice; /* Handle to the saved color environment */
  2393.     CTabHandle offColors;   /* Colors for off-screen environments */
  2394.     Rect       offRect;     /* Rectangle of off-screen environments */
  2395.     Rect       circleRect;  /* Rectangles for circle-drawing */
  2396.     short      count;       /* Generic counter */
  2397.     RGBColor   aColor;      /* Color used for drawing off screen */
  2398.     OSErr      error;       /* Error return from off-screen creation */
  2399.     /* Set up the rectangle for the off-screen graphics environments */
  2400.     SetRect( &offRect, 0, 0, 256, 256 );
  2401.     /* Get the color table for the gray off-screen graphics environment */
  2402.     offColors = GetCTable( rGrayClut );
  2403.     /* Create the gray off-screen graphics environment */
  2404.     error = CreateOffScreen( &offRect, kOffDepth, offColors,
  2405.             &grayPort, &grayDevice );
  2406.     if (error == noErr)
  2407.     {
  2408.         /* Get the color table for the color off-screen graphics environment */
  2409.         offColors = GetCTable( rColorClut );
  2410.         /* Create the color off-screen graphics environment */
  2411.         error = CreateOffScreen( &offRect, kOffDepth, offColors,
  2412.                 &colorPort, &colorDevice );
  2413.         if (error == noErr)
  2414.         {
  2415.             /* Save the current graphics environment */
  2416.             GetPort( &savedPort );
  2417.             savedDevice = GetGDevice();
  2418.             /* Set the current graphics environment to the gray one */
  2419.             SetPort( (GrafPtr)grayPort );
  2420.             SetGDevice( grayDevice );
  2421.             /* Draw gray-scale ramp into the gray off-screen environment */
  2422.             for (count = 0; count < 256; ++count)
  2423.             {
  2424.                 aColor.red = aColor.green = aColor.blue = count * 257;
  2425.                 RGBForeColor( &aColor );
  2426.                 MoveTo( 0, count );
  2427.                 LineTo( 255, count );
  2428.             }
  2429.             /* Copy gray ramp into color off-screen colorized with green */
  2430.             SetPort( (GrafPtr)colorPort );
  2431.             SetGDevice( colorDevice );
  2432.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  2433.             RGBForeColor( &aColor );
  2434.             CopyBits( &((GrafPtr)grayPort)->portBits,
  2435.                     &((GrafPtr)colorPort)->portBits,
  2436.                     &grayPort->portRect,
  2437.                     &colorPort->portRect,
  2438.                     srcCopy | ditherCopy, nil );
  2439.             /* Draw red, green, and blue circles */
  2440.             PenSize( 8, 8 );
  2441.             aColor.red = 0xFFFF; aColor.green = 0x0000; aColor.blue = 0x0000;
  2442.             RGBForeColor( &aColor );
  2443.             circleRect = colorPort->portRect;
  2444.             FrameOval( &circleRect );
  2445.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  2446.             RGBForeColor( &aColor );
  2447.             InsetRect( &circleRect, 20, 20 );
  2448.             FrameOval( &circleRect );
  2449.             aColor.red = 0x0000; aColor.green = 0x0000; aColor.blue = 0xFFFF;
  2450.             RGBForeColor( &aColor );
  2451.             InsetRect( &circleRect, 20, 20 );
  2452.             FrameOval( &circleRect );
  2453.             /* Copy the color off-screen environment to the current port */
  2454.             SetPort( savedPort );
  2455.             SetGDevice( savedDevice );
  2456.             CopyBits( &((GrafPtr)colorPort)->portBits, &savedPort->portBits,
  2457.                     &colorPort->portRect, &savedPort->portRect,
  2458.                     srcCopy, nil );
  2459.             /* Dispose of the off-screen graphics environments */
  2460.             DisposeOffScreen( grayPort, grayDevice );
  2461.             DisposeOffScreen( colorPort, colorDevice );
  2462.         }
  2463.     }
  2464. }
  2465. Two off-screen graphics environments are created in the same way. A rectangle that’s 256 pixels wide by 256 pixels high and with its top-left coordinate at (0, 0) is created in the offRect local variable. 'clut' resources are loaded from the application’s resource fork to use as the color tables of the two off-screen graphics environments; a gray-scale 'clut' in the first case and a full-color 'clut' in the second case. Then, CreateOffScreen is called with the rectangle, color table, and a hard-coded pixel depth of eight bits per pixel.
  2466. If CreateOffScreen returns noErr in both cases, then the current graphics environment is saved so that it can be restored later. Graphics environments consist of the current port and the current GDevice. The current GrafPort or CGrafPort is saved with _GetPort. The current GDevice is saved with _GetGDevice.
  2467. The gray-scale off-screen graphics environment is set as the current graphics environment by calling _SetPort with its CGrafPort and calling _SetGDevice with its GDevice. A vertical gray ramp is drawn into this graphics environment with the usual set of QuickDraw calls. This graphics environment’s pixel image is then copied to the full-color off-screen graphics environment with dithering and colorization with green (dithering requires 32-Bit QuickDraw and consistent colorization requires system software version 7.0; both of these features are described in Konstantin Othmer’s article “QuickDraw’s CopyBits Procedure: Better Than Ever in System 7.0” in Issue 6 of develop). Before this copy happens, the full-color off-screen graphics environment must be set as the current one. Once this is done, _CopyBits can properly map colors from the gray-scale off-screen graphics environment to the full-color one which gets a green ramp image.
  2468. Red, green, and blue concentric circles are drawn into the full-color off-screen graphics environment over the green ramp. This image is then copied to the graphics environment that was the current one when ExerciseOffScreen was called. To do this, the saved graphics environment is set as the current one by what should now be the familiar calls to _SetPort and _SetGDevice. The off-screen image is then copied to the saved graphics environment with _CopyBits.
  2469. Finally, the two off-screen graphics environments are disposed of by calling the DisposeOffScreen routine that’s defined in the section “All Fall Down”  earlier in this Note.
  2470. Put That Checkbook Away!
  2471. The previous section covered the basics of creating and using off-screen graphics environments. This is good enough for many, if not most, needs of off-screen drawing. But there are variations to creating and maintaining an off-screen graphics environment for specific cases. This section discusses a few of the more common cases.
  2472. About That Creation Thing . . .
  2473. The CreateOffScreen routine, defined in Listing 1, takes three pieces of information: the boundary rectangle, the desired pixel depth, and the desired color table. But there’s much more to these pieces than ExerciseOffScreen shows. This section describes these pieces in more detail.
  2474. The first parameter to CreateOffScreen is a rectangle which determines the size and coordinate system of the off-screen graphics environment. Usually, the top-left corner of the rectangle has the coordinate (0, 0) because it’s usually easiest to draw everything using coordinates that can also be thought of as the horizontal and vertical distance in pixels from the top-left corner of the graphics environment. But in some cases, it’s more convenient to have the (0, 0) coordinate somewhere else, and passing CreateOffScreen a rectangle with a nonzero coordinate in the top-left corner is an easy way to do this. The coordinate system can be translated after the off-screen graphics environment is created by using the _SetOrigin routine that’s described on pages 153 through 155 of Inside Macintosh Volume I.
  2475. Warning:    As Inside Macintosh Volume I, page 154, notes, the clip region of the port “sticks” to the coordinate system when you call _SetOrigin. If _SetOrigin offsets the coordinate system by a large amount, then the clip region might be moved completely outside of the port’s drawing area, and nothing can be drawn into that port. After calling _SetOrigin, you should set the clip region so that you can continue drawing into the port.
  2476. The number of bits per pixel implies the maximum number of available colors in a graphics environment, at least roughly speaking. The relationship between the number of bits per pixel and the number of available colors is discussed in the “Graphics Overview” chapter of Inside Macintosh Volume VI, pages 16-8 through 16-9.
  2477. If an indexed-color graphics environment is being made, then a color table must be passed to CreateOffScreen. In ExerciseOffScreen, the color table is retrieved from a 'clut' resource that’s in the application’s resource fork with a call to _GetCTable. Because CreateOffScreen clones this color table, this 'clut' resource can be purgeable so that it can be thrown out if its memory is needed for other purposes. _GetCTable can also be passed some special constants that tell it to allocate various system color tables that can also be passed to CreateOffScreen. These special constants are described on page 17-18 of the “Color QuickDraw” chapter of Inside Macintosh Volume VI. _GetCTable allocates memory for these system color tables, so they should be disposed of after you’re done with them.
  2478. A color table could also be built from scratch by allocating it with a call to _NewHandle and then initializing it by hand. The ColorTable structure is documented on pages 48 through 49 of Inside Macintosh Volume V. Here’s what each of the fields should be set to:
  2479. ctSeed    identification value. This is an arbitrary value that should be changed any time the contents of the color table change so that the inverse table can be kept current. When Color QuickDraw draws anything, it compares the ctSeed of the color table of the PixMap of the current GDevice against the iTabSeed field of the inverse table of the current GDevice. If they’re the same, then Color QuickDraw uses colors according to that inverse table. If they’re different, then Color QuickDraw first rebuilds the inverse table according to the new color table’s contents and its iTabSeed is set to the value of the new color table’s ctSeed; then the rebuilt inverse table is used.
  2480.     When _CopyBits is called with the srcCopy transfer mode, the ctSeed fields of the source and destination pixel maps are compared. If they’re the same, then _CopyBits simply transfers the source pixels to the destination with no mapping of colors. If they’re different, then _CopyBits checks each entry of the color tables to determine whether they have the same colors for the same pixel values. If they do, then _CopyBits again simply transfers the source pixels to the destination with no mapping of colors. If they don’t, then _CopyBits maps colors in the source PixMap to the colors in the current graphics environment according to the inverse table of the current GDevice. The ctSeed field of a color table should be changed whenever its contents are changed so that _CopyBits doesn’t make the wrong assumptions about the equality of the source and destination color tables.
  2481.     You can get a seed value for a new color table by assigning to it the result of the _GetCTSeed routine, documented in the “Color Manager” chapter of Inside Macintosh Volume V, page 143. If the contents of an existing color table are changed, then it should be passed to the _CTabChanged routine which assigns a new value to its ctSeed field. If the _CTabChanged routine isn’t available (it’s available with 32-Bit QuickDraw and is included with the system beginning with system software version 7.0), then the ctSeed field should be given a new value with another call to _GetCTSeed.
  2482. ctFlags    indicates the Boolean characteristics of a color table. If the most significant bit of ctFlags is clear, then the value field of each ColorSpec entry in the ctTable array is interpreted as the pixel value for the color that’s specified in the rgb field in the same ColorSpec entry. You can build a color table with nonconsecutive pixel values this way. If this bit is set, then all the value fields in the color table are ignored and the index of each ColorSpec record in the ctTable array is that record’s pixel value. It’s your choice whether to clear this bit and set the value fields or set this bit and ignore the value fields; traditionally this bit is clear for off-screen color tables.
  2483.     If the next most significant bit of ctFlags is set, then the value field of each ColorSpec record in the ctTable array is used by _CopyBits as an index into the color palette that’s attached to the destination window, and the rgb field is ignored. This is documented in the “Palette Manager” chapter of Inside Macintosh Volume VI, page 20-17.
  2484.     The other bits are reserved for future use. If you create a color table from scratch, these other bits must be set to zero. If you use a color table that’s generated by the system, then these bits must be preserved.
  2485. ctSize    the number of color table entries minus 1. Normally, this field is set to 1, 3, 15, or 255 for 1-, 2-, 4-, and 8-bits per pixel, respectively. In special cases, it’s reasonable to have less than the maximum number of entries for the pixel depth. For example, a color table for an 8-bit per pixel graphics environment could have just 150 entries, in which case the ctSize field should hold 149. For this case, it’s still important to allocate as much space in the color table for the maximum number of entries for a pixel depth and clear the entries you’re not using to zero because some parts of Color QuickDraw assume the size of a color table based on the pixel depth.
  2486. ctTable    array of colors and pixel values. This table defines all the available colors in the color table and their pixel values. The value field of each ColorSpec record indicates that color’s pixel value if the most significant bit of ctFlags is clear. It’s ignored if the most significant bit of ctFlags is set. The value field is used as an index into a palette if the next most significant bit of ctFlags is set, in which case the rgb field is ignored. See the discussion of the ctFlags field earlier in this Note for more details.
  2487. Warning:    Color QuickDraw’s text-drawing routines assume that the color table of the destination graphics environment has the maximum number of colors for the pixel depth of the graphics environment, and that white is the first entry in the color table and black is the last entry. If these conditions aren’t satisfied, then the resulting image is unpredictable.
  2488. The code fragment in Listing 6 shows how to allocate a 256-entry color table from scratch. Color tables have a variable size, so the _NewHandle call has to calculate the size of the ColorTable record plus the maximum number of color table entries for the pixel depth multiplied by the size of a ColorSpec record. kNumColors - 1 is used in the calculation because the size of the ColorTable record includes the size of one ColorSpec entry in most development environments.
  2489. MPW Pascal Listing 6
  2490. CONST
  2491.    kNumColors = 256; {Number of color table entries}
  2492. VAR
  2493.    newColors: CTabHandle; {Handle to the new color table}
  2494.    index:     Integer;    {Index into the table of colors}
  2495. (* Allocate memory for the color table *)
  2496. newColors := CTabHandle(NewHandleClear(SizeOf (ColorTable) +
  2497.       SizeOf(ColorSpec) * (kNumColors - 1)));
  2498. IF newColors <> NIL THEN
  2499.    BEGIN
  2500.       (* Initialize the fields *)
  2501.       newColors^^.ctSeed := GetCTSeed;
  2502.       newColors^^.ctFlags := 0;
  2503.       newColors^^.ctSize := kNumColors - 1;
  2504.       (* Initialize the table of colors *)
  2505.       FOR index := 0 TO kNumColors - 1 DO
  2506.          BEGIN
  2507.             newColors^^.ctTable[index].value := index;
  2508.             newColors^^.ctTable[index].rgb.red := someRedValue;
  2509.             newColors^^.ctTable[index].rgb.green := someGreenValue;
  2510.             newColors^^.ctTable[index].rgb.blue := someBlueValue
  2511.          END
  2512.    END
  2513. MPW C Listing 6
  2514. #define kNumColors 256 /* Number of color table entries */
  2515. CTabHandle newColors; /* Handle to the new color table */
  2516. short      index;     /* Index into the table of colors */
  2517. /* Allocate memory for the color table */
  2518. newColors = (CTabHandle)NewHandleClear( sizeof (ColorTable) +
  2519.         sizeof (ColorSpec) * (kNumColors - 1) );
  2520. if (newColors != nil)
  2521. {
  2522.     /* Initialize the fields */
  2523.     (**newColors).ctSeed = GetCTSeed();
  2524.     (**newColors).ctFlags = 0;
  2525.     (**newColors).ctSize = kNumColors - 1;
  2526.     /* Initialize the table of colors */
  2527.     for (index = 0; index < kNumColors; index++)
  2528.     {
  2529.         (**newColors).ctTable[index].value = index;
  2530.         (**newColors).ctTable[index].rgb.red = someRedValue;
  2531.         (**newColors).ctTable[index].rgb.green = someGreenValue;
  2532.         (**newColors).ctTable[index].rgb.blue = someBlueValue;
  2533.     }
  2534. }
  2535. Changing Your Environment
  2536. After you create an off-screen graphics environment with certain dimensions, you might later want to change its size, depth, or color table without creating a completely new graphics environment from scratch and without needing to redraw the existing image. The UpdateOffScreen routine in Listing 7 shows just one way to do this. It takes the same parameters that CreateOffScreen (defined in Listing 1) does, but instead of creating a new CGrafPort and GDevice, it alters the ones that you pass through the updPort and updGDevice parameters. If the newBounds parameter specifies an empty rectangle, then the existing boundary rectangle for the off-screen graphics environment is used. Similarly, if newDepth is zero, then the existing depth is used; and if the newColors parameter is NIL, then the existing color table is used. UpdateOffScreen alters the given CGrafPort and GDevice to the new settings, but it completely replaces the PixMap. After all the alterations are made, the old PixMap’s image is copied to the new PixMap’s image, and then the old PixMap and its image are disposed.
  2537. MPW Pascal Listing 7
  2538. FUNCTION UpdateOffScreen(
  2539.    newBounds:  Rect;       {New bounding rectangle of off-screen}
  2540.    newDepth:   Integer;    {New number of bits per pixel in off-screen}
  2541.    newColors:  CTabHandle; {New color table to assign to off-screen}
  2542.    updPort:    CGrafPtr;   {Returns a pointer to the updated CGrafPort}
  2543.    updGDevice: GDHandle    {Returns a handle to the updated GDevice}
  2544.    ): OSErr;
  2545.    CONST
  2546.       kMaxRowBytes = $3FFE; {Maximum number of bytes per row of pixels}
  2547.    VAR
  2548.       newPixMap:   PixMapHandle; {Handle to the new off-screen PixMap}
  2549.       oldPixMap:   PixMapHandle; {Handle to the old off-screen PixMap}
  2550.       bounds:      Rect;         {Boundary rectangle of off-screen}
  2551.       depth:       Integer;      {Depth of the off-screen PixMap}
  2552.       bytesPerRow: Integer;      {Number of bytes per row in the PixMap}
  2553.       colors:      CTabHandle;   {Colors for the off-screen PixMap}
  2554.       savedFore:   RGBColor;     {Saved foreground color}
  2555.       savedBack:   RGBColor;     {Saved background color}
  2556.       aColor:      RGBColor;     {Used to set foreground and background color}
  2557.       qdVersion:   LongInt;      {Version of QuickDraw currently in use}
  2558.       savedPort:   GrafPtr;      {Pointer to GrafPort used for save/restore}
  2559.       savedDevice: GDHandle;     {Handle to GDevice used for save/restore}
  2560.       savedState:  SignedByte;   {Saved state of color table handle}
  2561.       error:       OSErr;        {Returns error code}
  2562. BEGIN
  2563.    (* Initialize a few things before we begin *)
  2564.    newPixMap := NIL;
  2565.    error := noErr;
  2566.    (* Keep the old bounds rectangle, or get the new one *)
  2567.    IF EmptyRect(newBounds) THEN
  2568.       bounds := updPort^.portRect
  2569.    ELSE
  2570.       bounds := newBounds;
  2571.    (* Keep the old depth, or get the old one *)
  2572.    IF newDepth = 0 THEN
  2573.       depth := updPort^.portPixMap^^.pixelSize
  2574.    ELSE
  2575.       depth := newDepth;
  2576.    (* Get the old clut, or save new clut’s state and make it nonpurgeable *)
  2577.    IF newColors = NIL THEN
  2578.       colors := updPort^.portPixMap^^.pmTable
  2579.    ELSE
  2580.       BEGIN
  2581.          savedState := HGetState(Handle(newColors));
  2582.          HNoPurge(Handle(newColors));
  2583.          colors := newColors;
  2584.       END;
  2585.    (* Calculate the number of bytes per row in the off-screen PixMap *)
  2586.    bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  2587.    (* Get the current QuickDraw version *)
  2588.    error := Gestalt (gestaltQuickdrawVersion, qdVersion);
  2589.    error := noErr;
  2590.    (* Make sure depth is indexed or depth is direct and 32-Bit QD installed *)
  2591.    IF (depth = 1) OR (depth = 2) OR (depth = 4) OR (depth = 8) OR
  2592.          (((depth = 16) OR (depth = 32)) AND (qdVersion >= gestalt32BitQD)) THEN
  2593.       BEGIN
  2594.          (* Maximum number of bytes per row is 16,382; make sure within range *)
  2595.          IF bytesPerRow <= kMaxRowBytes THEN
  2596.             BEGIN
  2597.                (* Make sure a color table is provided if the depth is indexed *)
  2598.                IF depth <= 8 THEN
  2599.                   IF colors = NIL THEN
  2600.                      (* Indexed depth and clut is NIL; is parameter error *)
  2601.                      error := paramErr;
  2602.             END
  2603.          ELSE
  2604.             (* # of bytes per row is more than 16,382; is parameter error *)
  2605.             error := paramErr;
  2606.       END
  2607.    ELSE
  2608.       (* Pixel depth isn’t valid; is parameter error *)
  2609.       error := paramErr;
  2610.    (* If sanity checks succeed, attempt to update the graphics environment *)
  2611.    IF error = noErr THEN
  2612.       BEGIN
  2613.          (* Allocate a new PixMap *)
  2614.          newPixMap := PixMapHandle(NewHandleClear(SizeOf(PixMap)));
  2615.          IF newPixMap <> NIL THEN
  2616.               BEGIN
  2617.                (* Initialize the new PixMap for off-screen drawing *)
  2618.                error := SetUpPixMap(depth, bounds, colors, bytesPerRow,
  2619.                      newPixMap);
  2620.                IF error = noErr THEN
  2621.                   BEGIN
  2622.                      (* Save old PixMap and install new, initialized one *)
  2623.                      oldPixMap := updPort^.portPixMap;
  2624.                      updPort^.portPixMap := newPixMap;
  2625.                      (* Save current port & GDevice; set ones we’re updating *)
  2626.                      GetPort(savedPort);
  2627.                      savedDevice := GetGDevice;
  2628.                      SetPort(GrafPtr(updPort));
  2629.                      SetGDevice(updGDevice);
  2630.                      (* Set portRect, visRgn, clipRgn to given bounds rect *)
  2631.                      updPort^.portRect := bounds;
  2632.                      RectRgn(updPort^.visRgn, bounds);
  2633.                      ClipRect(bounds);
  2634.                      (* Update the GDevice *)
  2635.                      IF newPixMap^^.pixelSize <= 8 THEN
  2636.                         updGDevice^^.gdType := clutType
  2637.                      ELSE
  2638.                         updGDevice^^.gdType := directType;
  2639.                      updGDevice^^.gdPMap := newPixMap;
  2640.                      updGDevice^^.gdRect := newPixMap^^.bounds;
  2641.                      (* Set color-device bit if PixMap isn’t black & white *)
  2642.                      IF newPixMap^^.pixelSize > 1 THEN
  2643.                         SetDeviceAttribute(updGDevice, gdDevType, TRUE);
  2644.                      else
  2645.                         SetDeviceAttribute(updGDevice, gdDevType, FALSE);
  2646.                      (* Save current fore/back colors and set to B&W *)
  2647.                      GetForeColor(savedFore);
  2648.                      GetBackColor(savedBack);
  2649.                      aColor.red := 0; aColor.green := 0; aColor.blue := 0;
  2650.                      RGBForeColor(aColor);
  2651.                      aColor.red := $FFFF;
  2652.                      aColor.green := $FFFF;
  2653.                      aColor.blue := $FFFF;
  2654.                      RGBBackColor(aColor);
  2655.                      (* Copy old image to the new graphics environment *)
  2656.                      HLock(Handle(oldPixMap));
  2657.                      CopyBits(BitMapPtr(oldPixMap^)^, GrafPtr(updPort)^.portBits,
  2658.                            oldPixMap^^.bounds, updPort^.portRect,
  2659.                            srcCopy, NIL);
  2660.                      HUnlock(Handle(oldPixMap));
  2661.                      (* Restore the foreground/background color *)
  2662.                      RGBForeColor(savedFore);
  2663.                      RGBBackColor(savedBack);
  2664.                      (* Restore the saved port *)
  2665.                      SetPort(savedPort);
  2666.                      SetGDevice(savedDevice);
  2667.                      (* Get rid of the old PixMap and its dependents *)
  2668.                      DisposPtr(oldPixMap^^.baseAddr);
  2669.                      DisposeCTable(oldPixMap^^.pmTable);
  2670.                      DisposHandle(Handle(oldPixMap));
  2671.                   END;
  2672.             END
  2673.          ELSE
  2674.               error := MemError;
  2675.      END;
  2676.    (* Restore the given state of the color table *)
  2677.    IF colors <> NIL THEN
  2678.       HSetState(Handle(colors), savedState);
  2679.    (* One Last Look Around The House Before We Go… *)
  2680.    IF error <> noErr THEN
  2681.       BEGIN
  2682.          IF newPixMap <> NIL THEN
  2683.             BEGIN
  2684.                IF newPixMap^^.pmTable <> NIL THEN
  2685.                   DisposCTable(newPixMap^^.pmTable);
  2686.                IF newPixMap^^.baseAddr <> NIL THEN
  2687.                   DisposPtr(newPixMap^^.baseAddr);
  2688.                DisposHandle(Handle(newPixMap));
  2689.             END;
  2690.       END;
  2691.    UpdateOffScreen := error;
  2692. END;
  2693. MPW C Listing 7
  2694. #define kMaxRowBytes 0x3FFE /* Maximum number of bytes in a row of pixels */
  2695. OSErr UpdateOffScreen(
  2696.     Rect       *newBounds, /* New bounding rectangle of off-screen */
  2697.     short      newDepth,   /* New number of bits per pixel in off-screen */
  2698.     CTabHandle newColors,  /* New color table to assign to off-screen */
  2699.     CGrafPtr   updPort,    /* Returns a pointer to the updated CGrafPort */
  2700.     GDHandle   updGDevice) /* Returns a handle to the updated GDevice */
  2701. {
  2702.     PixMapHandle newPixMap;   /* Handle to the new off-screen PixMap */
  2703.     PixMapHandle oldPixMap;   /* Handle to the old off-screen PixMap */
  2704.     Rect         bounds;      /* Boundary rectangle of off-screen */
  2705.     short        depth;       /* Depth of the off-screen PixMap */
  2706.     short        bytesPerRow; /* Number of bytes per row in the PixMap */
  2707.     CTabHandle   colors;      /* Colors for the off-screen PixMap */
  2708.     RGBColor     savedFore;   /* Saved foreground color */
  2709.     RGBColor     savedBack;   /* Saved background color */
  2710.     RGBColor     aColor;      /* Used to set foreground and background color */
  2711.     long         qdVersion;   /* Version of QuickDraw currently in use */
  2712.     GrafPtr      savedPort;   /* Pointer to GrafPort used for save/restore */
  2713.     GDHandle     savedDevice; /* Handle to GDevice used for save/restore */
  2714.     SignedByte   savedState;  /* Saved state of color table handle */
  2715.     OSErr        error;       /* Returns error code */
  2716.     /* Initialize a few things before we begin */
  2717.     newPixMap = nil;
  2718.     error = noErr;
  2719.     /* Keep the old bounds rectangle, or get the new one */
  2720.     if (EmptyRect( newBounds ))
  2721.         bounds = updPort->portRect;
  2722.     else
  2723.         bounds = *newBounds;
  2724.     /* Keep the old depth, or get the old one */
  2725.     if (newDepth == 0)
  2726.         depth = (**updPort->portPixMap).pixelSize;
  2727.     else
  2728.         depth = newDepth;
  2729.     /* Get the old clut, or save new clut’s state and make it nonpurgeable */
  2730.     if (newColors == nil)
  2731.         colors = (**updPort->portPixMap).pmTable;
  2732.     else
  2733.     {
  2734.         savedState = HGetState( (Handle)newColors );
  2735.         HNoPurge( (Handle)newColors );
  2736.         colors = newColors;
  2737.     }
  2738.     /* Calculate the number of bytes per row in the off-screen PixMap */
  2739.     bytesPerRow = ((depth * (bounds.right - bounds.left) + 31) >> 5) << 2;
  2740.     /* Get the current QuickDraw version */
  2741.     (void)Gestalt( gestaltQuickdrawVersion, &qdVersion );
  2742.     /* Make sure depth is indexed or depth is direct and 32-Bit QD installed */
  2743.     if (depth == 1 || depth == 2 || depth == 4 || depth == 8 ||
  2744.             ((depth == 16 || depth == 32) && qdVersion >= gestalt32BitQD))
  2745.     {
  2746.         /* Maximum number of bytes per row is 16,382; make sure within range */
  2747.         if (bytesPerRow <= kMaxRowBytes)
  2748.         {
  2749.             /* Make sure a color table is provided if the depth is indexed */
  2750.             if (depth <= 8)
  2751.                 if (colors == nil)
  2752.                     /* Indexed depth and clut is NIL; is parameter error */
  2753.                     error = paramErr;
  2754.         }
  2755.         else
  2756.             /* # of bytes per row is more than 16,382; is parameter error */
  2757.             error = paramErr;
  2758.     }
  2759.     else
  2760.         /* Pixel depth isn’t valid; is parameter error */
  2761.         error = paramErr;
  2762.     /* If sanity checks succeed, attempt to create a new graphics environment */
  2763.     if (error == noErr)
  2764.     {
  2765.         /* Allocate a new PixMap */
  2766.         newPixMap = (PixMapHandle)NewHandleClear( sizeof (PixMap) );
  2767.         if (newPixMap != nil)
  2768.         {
  2769.             /* Initialize the new PixMap for off-screen drawing */
  2770.             error = SetUpPixMap( depth, &bounds, colors, bytesPerRow, newPixMap );
  2771.             if (error == noErr)
  2772.             {
  2773.                 /* Save the old PixMap and install the new, initialized one */
  2774.                 oldPixMap = updPort->portPixMap;
  2775.                 updPort->portPixMap = newPixMap;
  2776.                 /* Save current port & GDevice and set ones we’re updating */
  2777.                 GetPort( &savedPort );
  2778.                 savedDevice = GetGDevice();
  2779.                 SetPort( (GrafPtr)updPort );
  2780.                 SetGDevice( updGDevice );
  2781.                 /* Set portRect, visRgn, and clipRgn to the given bounds rect */
  2782.                 updPort->portRect = bounds;
  2783.                 RectRgn( updPort->visRgn, &bounds );
  2784.                 ClipRect( &bounds );
  2785.                 /* Update the GDevice */
  2786.                 if ((**newPixMap).pixelSize <= 8)
  2787.                     (**updGDevice).gdType = clutType;
  2788.                 else
  2789.                     (**updGDevice).gdType = directType;
  2790.                 (**updGDevice).gdPMap = newPixMap;
  2791.                 (**updGDevice).gdRect = (**newPixMap).bounds;
  2792.                 /* Set color-device bit if PixMap isn’t black & white */
  2793.                 if ((**newPixMap).pixelSize > 1)
  2794.                     SetDeviceAttribute( updGDevice, gdDevType, true );
  2795.                 else
  2796.                     SetDeviceAttribute( updGDevice, gdDevType, false );
  2797.                 /* Save current foreground/background colors and set to B&W */
  2798.                 GetForeColor( &savedFore );
  2799.                 GetBackColor( &savedBack );
  2800.                 aColor.red = aColor.green = aColor.blue = 0;
  2801.                 RGBForeColor( &aColor );
  2802.                 aColor.red = aColor.green = aColor.blue = 0xFFFF;
  2803.                 RGBBackColor( &aColor );
  2804.                 /* Copy old image to the new graphics environment */
  2805.                 HLock( (Handle)oldPixMap );
  2806.                 CopyBits( (BitMapPtr)*oldPixMap, &((GrafPtr) updPort)->portBits,
  2807.                         &(**oldPixMap).bounds, &updPort->portRect,
  2808.                         srcCopy, nil );
  2809.                 HUnlock( (Handle)oldPixMap );
  2810.                 /* Restore the foreground/background color */
  2811.                 RGBForeColor( &savedFore );
  2812.                 RGBBackColor( &savedBack );
  2813.                 /* Restore the saved port */
  2814.                 SetPort( savedPort );
  2815.                 SetGDevice( savedDevice );
  2816.                 /* Get rid of the old PixMap and its dependents */
  2817.                 DisposPtr( (**oldPixMap).baseAddr );
  2818.                 DisposeCTable( (**oldPixMap).pmTable ) ;
  2819.                 DisposHandle( (Handle)oldPixMap );
  2820.             }
  2821.         }
  2822.         else
  2823.             error = MemError();
  2824.     }
  2825.     /* Restore the given state of the color table */
  2826.     if (colors != nil)
  2827.         HSetState( (Handle)colors, savedState );
  2828.     /* One Last Look Around The House Before We Go… */
  2829.     if (error != noErr)
  2830.     {
  2831.         /* Some error occurred; dispose of everything we allocated */
  2832.         if (newPixMap != nil)
  2833.         {
  2834.             if ((**newPixMap).pmTable)
  2835.                 DisposCTable( (**newPixMap).pmTable );
  2836.             if ((**newPixMap).baseAddr)
  2837.                 DisposPtr ( (**newPixMap).baseAddr );
  2838.             DisposHandle( (Handle)newPixMap );
  2839.         }
  2840.     }
  2841.     return error;
  2842. }
  2843. UpdateOffScreen begins by checking the boundary rectangle, depth, or color table for emptiness, zero, or NIL, respectively. If any these satisfy that condition, then the existing characteristic is used. Next, the same sanity check that CreateOffScreen uses is done. If this sanity check succeeds, then a new PixMap is allocated, and then it’s initialized by the SetUpPixMap routine that’s given in Listing 2 which gives the new PixMap a new pixel image and its own copy of the color table. This new PixMap is installed into the CGrafPort after saving the reference to the old PixMap. Then, the portRect, visRgn, and clipRgn of the CGrafPort are set to the new boundary rectangle, as is the gdRect of the GDevice. The gdType of the GDevice is set either for the indexed-color or direct-color model, the gdPMap is set to the new PixMap, and the device attributes are set according to the pixel depth. Details about the settings for the CGrafPort and GDevice are in “Building the CGrafPort” and “Building the GDevice,” respectively, earlier in this Note.
  2844. At this point, the off-screen graphics environment is ready with its new characteristics, but it has garbage for an image because nothing has been drawn into it yet. The old PixMap, pixel image, and color table are still around, so _CopyBits transfers the old image into the altered graphics environment. _CopyBits handles the mapping from the old image’s characteristics to the new characteristics, so the altered graphics environment gets the best possible representation of the old image according to its new characteristics.
  2845. Changing the Off-Screen Color Table
  2846. Sometimes, it’s useful to change some or all of the colors in an off-screen color table, or to replace the off-screen color table with another one, so that the existing image in an indexed-color graphics environment appears with new colors. For example, if you had an off-screen image of a blue car and wanted to see what it looked like in green, you could change all of the shades of blue in the off-screen color table to green, and then _CopyBits the image to the screen. Notice that this is different from calling the UpdateOffScreen routine in the previous section with a different color table. That routine tries to reproduce the colors from the original image as best it can in the new set of colors. This section discusses the case in which you want the image’s colors to change.
  2847. The most obvious part of doing this is simply to get the color table from the off-screen pixel map’s pmTable field and modify the entries, or to dispose of the off-screen graphics environment’s current color table and assign the new one to it. There’s one more step to complete the process though. The discussion about GDevice records in “The Building Blocks” in this Note discusses inverse tables and how they go hand-in-hand with color tables. If you alter or replace the color table, you have to make sure that the inverse table of the off-screen drawing environment is rebuilt according to the new colors because Color QuickDraw uses that inverse table to know what pixel values to use for the specified color. You don’t have to rebuild the inverse table explicitly as long as you tell Color QuickDraw that the color table changed. To do this, all you have to do is make sure that the ctSeed of the changed or altered color table is set to a new value. And to do this, you can simply call _CTabChanged, which is documented on page 17-26 of the “Color QuickDraw” chapter of Inside Macintosh Volume VI. _CTabChanged is available beginning with 32-Bit QuickDraw and it’s available in system software version 7.0. If this routine isn’t available, then you can still tell Color QuickDraw that the color table has been changed by calling _GetCTSeed and assigning its result directly to your new color table’s ctSeed field.
  2848. The next time you draw into this off-screen drawing environment, Color QuickDraw checks the ctSeed of the environment’s color table against the iTabSeed of the inverse table of the environment’s GDevice. Because you changed the ctSeed of the color table either through _CTabChanged or _GetCTSeed, these two seeds are different so Color QuickDraw automatically rebuilds the inverse table of the current GDevice and then it copies the ctSeed of the color table to the iTabSeed of the rebuilt inverse table. Then drawing continues normally.
  2849. Follow That Screen!
  2850. One common need of off-screen graphics environments is that they have a depth and color table that matches a screen. The CreateOffScreen routine requires a color table for indexed-color environments, and a pixel depth. Because there can be more than one screen attached to a Macintosh system, you have to decide which screen’s depth and color table you should use. Typically, the depth and color table of the deepest screen that contains the area that you’re interested in (probably the area of a window) is used. Another option is to use the depth and color table of the screen that has the largest area of intersection with the area that you’re interested in. To find the depth and color table of the screen on which you want to base an off-screen graphics environment, you must use the list of graphics devices for all screens which is maintained by the system. Every GDevice record for a screen has a handle to that screen’s PixMap, and you can find the screen’s depth and color table there.
  2851. Listing 8 shows a routine called CreateScreenOffScreen which creates an off-screen graphics environment that has the depth and color table of a selected screen. The first parameter, bounds, specifies the rectangular part of the screen area in which you’re interested in global coordinates. The screenOption parameter specifies how you want the screen to be chosen. If you pass kDeepestScreen in this parameter, CreateScreenOffScreen creates the new off-screen graphics environment with the depth and color table of the deepest screen that intersects the bounds rectangle. If you instead pass kLargestScreenArea, then the new off-screen graphics environment is created with the depth and color table of the screen with the largest area of intersection with the bounds rectangle.
  2852. MPW Pascal Listing 8
  2853. TYPE
  2854.    ScreenOpt = (kDeepestScreen, kLargestAreaScreen);
  2855. FUNCTION CreateScreenOffScreen(
  2856.    bounds:         Rect;      {Global rectangle of part of screen to save}
  2857.    screenOption:   ScreenOpt; {Use deepest or largest intersection area screen?}
  2858.    VAR retPort:    CGrafPtr;  {Returns a pointer to the new CGrafPort}
  2859.    VAR retGDevice: GDHandle   {Returns a handle to the new GDevice}
  2860.    ): OSErr;
  2861.    VAR
  2862.       baseGDevice:  GDHandle;     {GDevice to base off-screen on}
  2863.       aGDevice:     GDHandle;     {Handle to each GDevice in the GDevice list}
  2864.       basePixMap:   PixMapHandle; {baseGDevice’s PixMap}
  2865.       maxArea:      LongInt;      {Largest intersection area found}
  2866.       area:         LongInt;      {Area of rectangle of intersection}
  2867.       commonRect:   Rect;         {Rectangle of intersection}
  2868.       normalBounds: Rect;         {bounds rectangle normalized to (0, 0)}
  2869.       error:        Integer;      {Error code}
  2870. BEGIN
  2871.    error := noErr;
  2872.    (* Different screen options require different algorithms *)
  2873.    IF screenOption = kDeepestScreen THEN
  2874.       (* Graphics Devices Manager tells us the deepest intersecting screen *)
  2875.       baseGDevice := GetMaxDevice(bounds)
  2876.    ELSE IF screenOption = kLargestAreaScreen THEN
  2877.       BEGIN
  2878.          (* Get a handle to the first GDevice in the GDevice list *)
  2879.          aGDevice := GetDeviceList;
  2880.     
  2881.          (* Keep looping until all GDevices have been checked *)
  2882.          maxArea := 0;
  2883.          baseGDevice := NIL;
  2884.          WHILE aGDevice <> NIL DO
  2885.             BEGIN
  2886.                (* Check to see whether screen rectangle and bounds intersect *)
  2887.                IF SectRect(aGDevice^^.gdRect, bounds, commonRect) THEN
  2888.                   BEGIN
  2889.                      (* Calculate area of intersection *)
  2890.                      area := LongInt(commonRect.bottom - commonRect.top) *
  2891.                            LongInt(commonRect.right - commonRect.left);
  2892.                      (* Keep track of largest area of intersection so far *)
  2893.                      IF area > maxArea THEN
  2894.                         BEGIN
  2895.                            maxArea := area;
  2896.                            baseGDevice := aGDevice;
  2897.                         END;
  2898.                   END;
  2899.                (* Go to the next GDevice in the GDevice list *)
  2900.                aGDevice := GetNextDevice(aGDevice);
  2901.             END;
  2902.       END
  2903.    ELSE
  2904.       error := paramErr;
  2905.    (* If no screens intersect the bounds, baseDevice is NIL *)
  2906.    IF (baseGDevice <> NIL) AND (error = noErr) THEN
  2907.       BEGIN
  2908.          (* Normalize the bounds rectangle *)
  2909.          normalBounds := bounds;
  2910.          OffsetRect(normalBounds, -normalBounds.left, -normalBounds.top);
  2911.          (* Create off-screen graphics environment w/ depth, clut of screen *)
  2912.          basePixMap := baseGDevice^^.gdPMap;
  2913.          error := CreateOffScreen(normalBounds, basePixMap^^.pixelSize,
  2914.                basePixMap^^.pmTable, retPort, retGDevice);
  2915.       END;
  2916.    CreateScreenOffScreen := error;
  2917. END;
  2918. MPW C Listing 8
  2919. enum
  2920. {
  2921.     kDeepestScreen,
  2922.     kLargestAreaScreen,
  2923. };
  2924. OSErr CreateScreenOffScreen(
  2925.     Rect     *bounds,      /* Global rectangle of part of screen to save */
  2926.     short    screenOption, /* Use deepest or largest intersection area screen */
  2927.     CGrafPtr *retPort,     /* Returns a pointer to the new CGrafPort */
  2928.     GDHandle *retGDevice)  /* Returns a handle to the new GDevice */
  2929. {
  2930.     GDHandle     baseGDevice;  /* GDevice to base off-screen on */
  2931.     GDHandle     aGDevice;     /* Handle to each GDevice in the GDevice list */
  2932.     PixMapHandle basePixMap;   /* baseGDevice’s PixMap */
  2933.     long         maxArea;      /* Largest intersection area found */
  2934.     long         area;         /* Area of rectangle of intersection */
  2935.     Rect         commonRect;   /* Rectangle of intersection */
  2936.     Rect         normalBounds; /* bounds rectangle normalized to (0, 0) */
  2937.     short        error;        /* Error code */
  2938.     error = noErr;
  2939.     /* Different screen options require different algorithms */
  2940.     if (screenOption == kDeepestScreen)
  2941.         /* Graphics Devices Manager tells us the deepest intersecting screen */
  2942.         baseGDevice = GetMaxDevice( bounds );
  2943.     else if (screenOption == kLargestAreaScreen)
  2944.     {
  2945.         /* Get a handle to the first GDevice in the GDevice list */
  2946.         aGDevice = GetDeviceList();
  2947.     
  2948.         /* Keep looping until all GDevices have been checked */
  2949.         maxArea = 0;
  2950.         baseGDevice = nil;
  2951.         while (aGDevice != nil)
  2952.         {
  2953.             /* Check to see whether screen rectangle and bounds intersect */
  2954.             if (SectRect( &(**aGDevice).gdRect, bounds, &commonRect ))
  2955.             {
  2956.                 /* Calculate area of intersection */
  2957.                 area = (long)(commonRect.bottom - commonRect.top) *
  2958.                        (long)(commonRect.right - commonRect.left);
  2959.                 /* Keep track of largest area of intersection found so far */
  2960.                 if (area > maxArea)
  2961.                 {
  2962.                     maxArea = area;
  2963.                     baseGDevice = aGDevice;
  2964.                 }
  2965.             }
  2966.             /* Go to the next GDevice in the GDevice list */
  2967.             aGDevice = GetNextDevice( aGDevice );
  2968.         }
  2969.     }
  2970.     else
  2971.         error = paramErr;
  2972.     /* If no screens intersect the bounds, baseDevice is NIL */
  2973.     if (baseGDevice != nil && error == noErr)
  2974.     {
  2975.         /* Normalize the bounds rectangle */
  2976.         normalBounds = *bounds;
  2977.         OffsetRect( &normalBounds, -normalBounds.left, -normalBounds.top );
  2978.         /* Create off-screen graphics environment w/ depth, clut of screen */
  2979.         basePixMap = (**baseGDevice).gdPMap;
  2980.         error = CreateOffScreen( &normalBounds, (**basePixMap).pixelSize,
  2981.                 (**basePixMap).pmTable, retPort, retGDevice );
  2982.     }
  2983.     return error;
  2984. }
  2985. Finding the deepest screen that intersects an on-screen area is trivially easy because there’s a Graphics Devices Manager routine that finds it called _GetMaxDevice which is documented on page 21-22 of the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI. The rectangle in global coordinates of the screen area you’re interested in is passed to _GetMaxDevice, and it returns a handle to the deepest screen that intersects that area, even if the area of intersection is as small as one pixel. If no screens intersect that area, then _GetMaxDevice returns NIL.
  2986. Finding the GDevice of the screen that has the maximum area of intersection with the screen area you’re interested in isn’t quite so easy because there’s no single Graphics Devices Manager routine to find this GDevice; you have to search the GDevice list yourself. You can get a handle to the first GDevice in the list by calling _GetDeviceList, and you can get a handle to each successive GDevice by calling _GetNextDevice. _GetDeviceList is documented on pages 21-21 through 21-22 of the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI, and _GetNextDevice is documented on page 21-22 of the same chapter. For each GDevice in the list, the area of intersection between the bounds and the gdRect of the GDevice is calculated. If the calculated area is the largest area of intersection found so far, then that area and the GDevice of that screen are remembered.
  2987. Once a winning GDevice has been chosen, either by being the deepest intersecting GDevice or the GDevice with the largest intersecting area, then CreateOffScreen routine is called with the pixel depth and color table of the PixMap of the GDevice, and the bounds rectangle normalized so that its top-left coordinate has the coordinates (0, 0). CreateOffScreen returns with the new off-screen graphics environment, and CreateScreenOffScreen returns this to the caller.
  2988. Choosing Your Off-Screen Memory
  2989. The CreateOffScreen routine in Listing 1 creates an off-screen graphics environment with its pixel image allocated as a nonrelocatable block in the application’s heap. But this isn’t the only way that the pixel image can be allocated. Pixel images can be big, and big blocks of nonrelocatable memory in your heap can be expensive in terms of performance, and they can cause a bad case of heap fragmentation. Why not put the pixel image in a relocatable block of memory instead? If there isn’t much free memory in your heap and if MultiFinder or system software version 7.0 is running, there’s memory that’s not being used by any open applications, called temporary memory (formerly called MultiFinder temporary memory). Why not use this area of memory for the pixel image? Some people have NuBus cards with plenty of memory on them. Why not move the pixel image out of the heaps altogether and instead use NuBus memory for the pixel image? All of these things can be done with simple modifications to what’s been discussed in this Note, and these modifications are discussed in the next few paragraphs.
  2990. How can pixel images be relocatable? After all, pixel images are referred to only by the baseAddr field of a PixMap, and the baseAddr is a pointer, not a handle. It’s true that while QuickDraw is being used to draw into a graphics environment, the pixel image had better not move or else QuickDraw will start drawing over the area of memory that the pixel image used to be rather than where it is. But if QuickDraw isn’t doing anything with the graphics environment, then it doesn’t care what happens to the pixel image as long as the baseAddr points to it once QuickDraw starts drawing into the graphics environment. This implies a strategy: allocate the pixel image as a relocatable block and let it float in the heap; when QuickDraw is about to to draw into the graphics environment or to copy from it, lock the pixel image and copy its master pointer into the baseAddr field of the PixMap; when the drawing or copying is finished, unlock the pixel image. There are many ways to implement this, and Listing 9 shows a code fragment for one very simple method.
  2991. MPW Pascal Listing 9
  2992.       ...
  2993.       (* Allocate the pixel image; use long multiplication to avoid overflow *)
  2994.       offBaseAddr := NewHandle(LongInt(bytesPerRow) * (bounds^.bottom -
  2995.             bounds^.top));
  2996.       IF offBaseAddr <> NIL THEN
  2997.          BEGIN
  2998.             (* Initialize fields common to indexed and direct PixMaps *)
  2999.             aPixMap^^.baseAddr := Ptr(offBaseAddr); (* Reference the image *)
  3000.       ...
  3001. PROCEDURE LockOffScreen(
  3002.    offScreenPort: CGrafPtr {Ptr to off-screen CGrafPort}
  3003.    );
  3004.    VAR
  3005.       offImageHnd: Handle; {Handle to the off-screen pixel image}
  3006. BEGIN
  3007.    (* Get the saved handle to the off-screen pixel image *)
  3008.    offImageHnd := Handle(offScreenPort^.portPixMap^^.baseAddr);
  3009.    (* Lock the handle to the pixel image *)
  3010.    HLock(offImageHnd);
  3011.    (* Put pixel image master pointer into baseAddr so that QuickDraw can use it *)
  3012.    offScreenPort^.portPixMap^^.baseAddr := offImageHnd^;
  3013. END;
  3014. PROCEDURE UnlockOffScreen(
  3015.    offScreenPort: CGrafPtr {Ptr to off-screen port}
  3016.    );
  3017.    VAR
  3018.       offImagePtr: Ptr;    {Pointer to the off-screen pixel image}
  3019.       offImageHnd: Handle; {Handle to the off-screen pixel image}
  3020. BEGIN
  3021.    (* Get the handle to the off-screen pixel image *)
  3022.    offImagePtr := offScreenPort^.portPixMap^^.baseAddr;
  3023.    offImageHnd := RecoverHandle(offImagePtr);
  3024.    (* Unlock the handle *)
  3025.    HUnlock(offImageHnd);
  3026.    (* Save the handle back in the baseAddr field *)
  3027.    offScreenPort^.portPixMap^^.baseAddr := Ptr(offImageHnd);
  3028. END;
  3029. MPW C Listing 9
  3030.         ...
  3031.         /* Allocate the pixel image; use long multiplication to avoid overflow */
  3032.         offBaseAddr = NewHandle( (unsigned long)bytesPerRow * (bounds->bottom -
  3033.                 bounds->top) );
  3034.         if (offBaseAddr != nil)
  3035.         {
  3036.             /* Initialize fields common to indexed and direct PixMaps */
  3037.             (**aPixMap).baseAddr = (Ptr)offBaseAddr; /* Reference the image */
  3038.         ...
  3039. void LockOffScreen(
  3040.     CGrafPtr offScreenPort) /* Pointer to the off-screen CGrafPort */
  3041. {
  3042.     Handle offImageHnd; /* Handle to the off-screen pixel image */
  3043.     /* Get the saved handle to the off-screen pixel image */
  3044.     offImageHnd = (Handle)(**offScreenPort->portPixMap).baseAddr;
  3045.     /* Lock the handle to the pixel image */
  3046.     HLock( offImageHnd );
  3047.     /* Put pixel image master pointer into baseAddr so that QuickDraw can use it */
  3048.     (**offScreenPort->portPixMap).baseAddr = *offImageHnd;
  3049. }
  3050. void UnlockOffScreen(
  3051.     CGrafPtr offScreenPort) /* Pointer to the off-screen CGrafPort */
  3052. {
  3053.     Ptr    offImagePtr; /* Pointer to the off-screen pixel image */
  3054.     Handle offImageHnd; /* Handle to the off-screen pixel image */
  3055.     /* Get the handle to the off-screen pixel image */
  3056.     offImagePtr = (**offScreenPort->portPixMap).baseAddr;
  3057.     offImageHnd = RecoverHandle( offImagePtr );
  3058.     /* Unlock the handle */
  3059.     HUnlock( offImageHnd );
  3060.     /* Save the handle back in the baseAddr field */
  3061.     (**offScreenPort->portPixMap).baseAddr = (Ptr)offImageHnd;
  3062. }
  3063. Listing 9 starts with a code fragment from the SetUpPixMap routine that’s modified so that it allocates a new handle for the off-screen pixel image instead of a new pointer. This handle is saved in the baseAddr field for now. When you’re about to draw into the off-screen graphics environment or to copy from it, the LockOffScreen routine in Listing 9 should be called with a pointer to the off-screen graphics environment’s CGrafPort as the parameter. It takes the handle to the pixel image from the baseAddr field of the off-screen graphics environment’s PixMap and passes it to _HLock which makes sure the pixel image can’t move in the heap. Then, the pixel image’s handle is dereferenced to get the master pointer to the pixel image, and this master pointer is copied into the baseAddr field. Now, QuickDraw can draw into or copy from the off-screen graphics environment.
  3064. When you’re finished drawing into the off-screen graphics environment, the pixel image should be unlocked, and the UnlockOffScreen routine in Listing 9 does this. The baseAddr field of the PixMap holds the pixel image’s master pointer, so this is passed to _RecoverHandle to get the pixel image’s handle. This handle is passed to _HUnlock to let the pixel image float in the heap again, and then this handle is saved in the baseAddr field.
  3065. One potentially useful addition to the LockOffScreen routine would be a call to _MoveHHi just before the call to _HLock. This helps reduce heap fragmentation while the pixel image is locked by moving it up as high in the heap as possible before locking it, allowing the other relocatable blocks to move without tripping over it. You have to be careful with _MoveHHi though because it not only moves the handle as high in the heap as possible, it moves other relocatable blocks out of the top of the heap to make room for the handle. This could involve moving huge amounts of memory, and it’s not unusual for _MoveHHi to take several seconds to do this.
  3066. How do you make an off-screen graphics environment that uses temporary memory for the pixel image? Temporary memory is allocated as handles, so there’s almost no difference between using temporary memory and using relocatable blocks in your own heap in the way that Listing 9 shows. All you have to do is replace the calls to _NewHandle, _HLock, and _HUnlock with calls to _TempNewHandle, _TempHLock, and _TempHUnlock. If temporary memory handles are real, then you don’t even have to replace the _HLock and _HUnlock calls—they work properly with temporary memory handles that are real.You can tell whether temporary memory handles are real or not by calling _Gestalt with the gestaltOSAttr selector. If the gestaltRealTempMemory bit is set, then all temporary memory handles are real. See the sections “About Temporary Memory” and “Using Temporary Memory” of Inside Macintosh Volume VI, pages 28-33 through 28-40.
  3067. How do you make an off-screen graphics environment that stores the pixel image on a NuBus memory card? The Macintosh Memory Manager doesn’t keep track of heaps on NuBus memory cards so it can’t be used to allocate memory on those cards, but if applications can use that card’s memory at will, then an application can set up the off-screen graphics environment with its pixel image in the NuBus card’s memory simply by setting the address of the card’s memory in the baseAddr field of the off-screen graphics environment’s PixMap instead of allocating anything.
  3068. If your NuBus memory card doesn’t require 32-bit addressing mode to access its memory, then setting the baseAddr to the address of the NuBus card’s memory is all you have to do. Some NuBus memory cards require its memory to be accessed in 32-bit addressing mode. Without 32-Bit QuickDraw, these memory cards can’t be used for storing the pixel image of an off-screen graphics environment because Color QuickDraw without 32-Bit QuickDraw always reads and writes pixel images in 24-bit addressing mode regardless of whether the pixel image is in main memory, on a NuBus video card, or on a NuBus memory card. With 32-Bit QuickDraw, Color QuickDraw automatically switches to 32-bit addressing mode before reading or writing a pixel image that’s on a video card. It won’t know to switch to 32-bit addressing mode if your off-screen graphics environment uses a pixel image on a NuBus memory card that’s not a video card, but you can tell it to make this switch by setting bit 2 of the pmVersion field of the PixMap for the off-screen graphics environment. This is normally done by logically ORing the pmVersion field with the predefined constant baseAddr32. See “About 32-Bit Addressing” in Issue 6 of develop, page 36, for more details about how QuickDraw handles addressing modes.
  3069. The GWorld Factor
  3070. In May 1989, 32-Bit QuickDraw was introduced as an extension to the system. While it had a lot of new features, the GWorld mechanism was the one that made the big news. GWorlds are off-screen graphics environments that you can have the system put together in one call. There’s no need for routines like CreateOffScreen, SetUpPixMap, or CreateGDevice—all of the off-screen graphics environment is set up with _NewGWorld. You can change most of its characteristics with _UpdateGWorld, set the current off-screen graphics environment with _SetGWorld, and get rid of the off-screen graphics environment with _DisposeGWorld. All the GWorld routines are described in the “Graphics Devices Manager” chapter of Inside Macintosh Volume VI. As an example, Listing 10 shows the same routine as the ExerciseOffScreen routine that’s shown in Listing 5, but Listing 10 uses GWorlds rather than the do-it-yourself routines that are defined in this Note.
  3071. MPW Pascal Listing 10
  3072. PROCEDURE ExerciseOffScreen;
  3073.    CONST
  3074.       kOffDepth  = 8;    {Number of bits per pixel in off-screen environment}
  3075.       rGrayClut  = 1600; {Resource ID of gray-scale clut}
  3076.       rColorClut = 1601; {Resource ID of full-color clut}
  3077.    VAR
  3078.       grayPort:    GWorldPtr;  {Graphics environment for gray off screen}
  3079.       colorPort:   GWorldPtr;  {Graphics environment for color off screen}
  3080.       savedPort:   GrafPtr;    {Pointer to the saved graphics environment}
  3081.       savedDevice: GDHandle;   {Handle to the saved color environment}
  3082.       offColors:   CTabHandle; {Colors for off-screen environments}
  3083.       offRect:     Rect;       {Rectangle of off-screen environments}
  3084.       circleRect:  Rect;       {Rectangles for circle-drawing}
  3085.       count:       Integer;    {Generic counter}
  3086.       aColor:      RGBColor;   {Color used for drawing off-screen}
  3087.       error:       OSErr;      {Error return from off-screen creation}
  3088. BEGIN
  3089.    (* Set up the rectangle for the off-screen graphics environments *)
  3090.    SetRect(offRect, 0, 0, 256, 256);
  3091.    (* Get the color table for the gray off-screen graphics environment *)
  3092.    offColors := GetCTable(rGrayClut);
  3093.    (* Create the gray off-screen graphics environment *)
  3094.    error := NewGWorld(grayPort, kOffDepth, offRect, offColors, NIL, []);
  3095.    IF error = noErr THEN
  3096.       BEGIN
  3097.          (* Get the color table for the color off-screen graphics environment *)
  3098.          offColors := GetCTable(rColorClut);
  3099.          (* Create the color off-screen graphics environment *)
  3100.          error := NewGWorld(colorPort, kOffDepth, offRect, offColors, NIL, []);
  3101.          IF error = noErr THEN
  3102.             BEGIN
  3103.                (* Save the current graphics environment *)
  3104.                GetGWorld(savedPort, savedDevice);
  3105.                (* Set the current graphics environment to the gray one *)
  3106.                SetGWorld(grayPort, NIL);
  3107.                (* Draw gray-scale ramp into the gray off-screen environment *)
  3108.                FOR count := 0 TO 255 DO
  3109.                   BEGIN
  3110.                      aColor.red := count * 257;
  3111.                      aColor.green := aColor.red;
  3112.                      aColor.blue := aColor.green;
  3113.                      RGBForeColor(aColor);
  3114.                      MoveTo(0, count);
  3115.                      LineTo(255, count);
  3116.                   END;
  3117.                (* Copy gray ramp into color off-screen colorized with green *)
  3118.                SetGWorld(colorPort, NIL);
  3119.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  3120.                RGBForeColor(aColor);
  3121.                CopyBits(GrafPtr(grayPort)^.portBits,
  3122.                      GrafPtr(colorPort)^.portBits,
  3123.                      grayPort^.portRect,
  3124.                      colorPort^.portRect,
  3125.                      srcCopy + ditherCopy, NIL);
  3126.                (* Draw red, green, and blue circles *)
  3127.                PenSize(8, 8);
  3128.                aColor.red := $FFFF; aColor.green := $0000; aColor.blue := $0000;
  3129.                RGBForeColor(aColor);
  3130.                circleRect := colorPort^.portRect;
  3131.                FrameOval(circleRect);
  3132.                aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;
  3133.                RGBForeColor(aColor);
  3134.                InsetRect(circleRect, 20, 20);
  3135.                FrameOval(circleRect);
  3136.                aColor.red := $0000; aColor.green := $0000; aColor.blue := $FFFF;
  3137.                RGBForeColor(aColor);
  3138.                InsetRect(circleRect, 20, 20);
  3139.                FrameOval(circleRect);
  3140.                (* Copy the color off-screen environment to the current port *)
  3141.                SetGWorld(savedPort, savedDevice);
  3142.                CopyBits(GrafPtr(colorPort)^.portBits,
  3143.                      savedPort^.portBits,
  3144.                      colorPort^.portRect,
  3145.                      savedPort^.portRect,
  3146.                      srcCopy, NIL);
  3147.                (* Dispose of the off-screen graphics environments *)
  3148.                DisposeGWorld grayPort);
  3149.                DisposeGWorld(colorPort);
  3150.             END;
  3151.       END;
  3152. END;
  3153. MPW C Listing 10
  3154. #define kOffDepth  8    /* Number of bits per pixel in off-screen environment */
  3155. #define rGrayClut  1600 /* Resource ID of gray-scale clut */
  3156. #define rColorClut 1601 /* Resource ID of full-color clut */
  3157. void ExerciseOffScreen()
  3158. {
  3159.     GWorldPtr  grayPort;    /* Graphics environment for gray off screen */
  3160.     GWorldPtr  colorPort;   /* Graphics environment for color off screen */
  3161.     CGrafPtr   savedPort;   /* Pointer to the saved graphics environment */
  3162.     GDHandle   savedDevice; /* Handle to the saved color environment */
  3163.     CTabHandle offColors;   /* Colors for off-screen environments */
  3164.     Rect       offRect;     /* Rectangle of off-screen environments */
  3165.     Rect       circleRect;  /* Rectangles for circle-drawing */
  3166.     short      count;       /* Generic counter */
  3167.     RGBColor   aColor;      /* Color used for drawing off-screen */
  3168.     OSErr      error;       /* Error return from off-screen creation */
  3169.     /* Set up the rectangle for the off-screen graphics environments */
  3170.     SetRect( &offRect, 0, 0, 256, 256 );
  3171.     /* Get the color table for the gray off-screen graphics environment */
  3172.     offColors = GetCTable( rGrayClut );
  3173.     /* Create the gray off-screen graphics environment */
  3174.     error = NewGWorld( &grayPort, kOffDepth, &offRect, offColors, nil, 0 );
  3175.     if (error == noErr)
  3176.     {
  3177.         /* Get the color table for the color off-screen graphics environment */
  3178.         offColors = GetCTable( rColorClut );
  3179.         /* Create the color off-screen graphics environment */
  3180.         error = NewGWorld( &colorPort, kOffDepth, &offRect, offColors, nil, 0 );
  3181.         if (error == noErr)
  3182.         {
  3183.             /* Save the current graphics environment */
  3184.             GetGWorld( &savedPort, &savedDevice );
  3185.             /* Set the current graphics environment to the gray one */
  3186.             SetGWorld( grayPort, nil );
  3187.             /* Draw gray-scale ramp into the gray off-screen environment */
  3188.             for (count = 0; count < 256; count++)
  3189.             {
  3190.                 aColor.red = aColor.green = aColor.blue = count * 257;
  3191.                 RGBForeColor( &aColor );
  3192.                 MoveTo( 0, count );
  3193.                 LineTo( 255, count );
  3194.             }
  3195.             /* Copy gray ramp into color off-screen colorized with green */
  3196.             SetGWorld( colorPort, nil );
  3197.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  3198.             RGBForeColor( &aColor );
  3199.             CopyBits( &((GrafPtr)grayPort)->portBits,
  3200.                     &((GrafPtr)colorPort)->portBits,
  3201.                     &grayPort->portRect,
  3202.                     &colorPort->portRect,
  3203.                     srcCopy | ditherCopy, nil );
  3204.             /* Draw red, green, and blue circles */
  3205.             PenSize( 8, 8 );
  3206.             aColor.red = 0xFFFF; aColor.green = 0x0000; aColor.blue = 0x0000;
  3207.             RGBForeColor( &aColor );
  3208.             circleRect = colorPort->portRect;
  3209.             FrameOval( &circleRect );
  3210.             aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;
  3211.             RGBForeColor( &aColor );
  3212.             InsetRect( &circleRect, 20, 20 );
  3213.             FrameOval( &circleRect );
  3214.             aColor.red = 0x0000; aColor.green = 0x0000; aColor.blue = 0xFFFF;
  3215.             RGBForeColor( &aColor );
  3216.             InsetRect( &circleRect, 20, 20 );
  3217.             FrameOval( &circleRect );
  3218.             /* Copy the color off-screen environment to the current port */
  3219.             SetGWorld( savedPort, savedDevice );
  3220.             CopyBits( &((GrafPtr)colorPort)->portBits,
  3221.                     &((GrafPtr)savedPort)->portBits,
  3222.                     &colorPort->portRect,
  3223.                     &savedPort->portRect,
  3224.                     srcCopy, nil );
  3225.             /* Dispose of the off-screen graphics environments */
  3226.             DisposeGWorld( grayPort );
  3227.             DisposeGWorld( colorPort );
  3228.         }
  3229.     }
  3230. }
  3231. _NewGWorld creates an off-screen graphics environment by creating a CGrafPort, PixMap, and GDevice—the same structures that you normally put together when you make an off-screen graphics environment yourself. In this aspect, and in fact in most aspects, there’s nothing magical about GWorlds. Do GWorlds make the CreateOffScreen, DisposeOffScreen, and their dependents useless? That depends on what your needs are. What follows are a few issues about off-screen drawing and how that determines whether you use your own routines, such as CreateOffScreen, to create and maintain off-screen graphics environments or whether you use GWorlds for the same purpose.
  3232. I Want the Best Performance!
  3233. As mentioned in the last paragraph, there’s nothing magical about GWorlds in most aspects. In one major aspect, there certainly is: the version of Color QuickDraw that runs with the 8•24 GC video card’s acceleration on knows about GWorlds and can cache their CGrafPort, PixMap, GDevice, inverse table, color table, and pixel image on the 8•24 GC card if there’s enough memory on it. When this is done, QuickDraw operations on the GWorld can be much faster than they’d normally be because the image data can stay in the card’s memory where the fast microprocessor is, and image data doesn’t have to move across NuBus in transfer operations between the GWorld and the screen. Additionally, these operations are executed asynchronously which increases the overall speed of your programs. For details about how the 8•24 GC card and GC QuickDraw work, see Guillermo Ortiz’s article, “Macintosh Display Card 8•24 GC: The Naked Truth,” in Issue 5 of develop.
  3234. 8•24 GC QuickDraw doesn’t know about the off-screen graphics environments that you create, so it doesn’t cache its structures. All QuickDraw commands that move image data between the off-screen graphics environment and the screen have to move the data across NuBus, and that slows down the operation in comparison to keeping all the image data on the card.
  3235. If you want the highest possible drawing and copying performance with the 8•24 GC card, you must use GWorlds for your off-screen graphics environments.
  3236. I Want to Use a NuBus Memory Card for My GWorld’s Off-Screen Pixel Image
  3237. One common desire is to use a NuBus memory card to hold a pixel image. Because GWorlds are so easy to set up, and because GWorlds have all the same parts that you can make for an off-screen graphics environment, it’s tempting to make a GWorld and then point the baseAddr of the GWorld’s PixMap at the NuBus card’s memory. But GWorlds are designed to be fairly atomic structures, so they can’t be changed in this way. You can change a GWorld’s dimensions, depth, and color table because there’s a routine (_UpdateGWorld) that is designed to change these things, but you can’t change the pixel image without risking future compatibility.
  3238. If you want to have an off-screen graphics environment use a NuBus video card to store the pixel image, you should set up your own off-screen graphics environment rather than use GWorlds. This is covered earlier in this Note in “Choosing Your Off-Screen Memory.”
  3239. I Want My Program to Work on All System Software Releases
  3240. GWorlds have been around since 32-Bit QuickDraw was released (while system software version 6.0.3 was current). Until system software version 7.0, 32-Bit QuickDraw was an optional part of the system, so you aren’t guaranteed use of GWorlds even under recent system software releases. Obviously, if GWorlds aren’t available and your program still has to work with off-screen graphics environments, then there’s no choice but to use your own routines for creating, maintaining, and disposing of off-screen graphics environments. What’s usually done in these cases is to check via _Gestalt whether GWorlds are available or not. If they aren’t, then you create your off-screen graphics environment with your own routines. If they are, then you can use GWorlds without having to take up memory with your code for creating off-screen graphics environments yourself.
  3241. Are We There Yet?
  3242. Reliable, understandable, and maintainable off-screen drawing routines means not taking short-cuts. The most common problems that people run into with off-screen drawing routines is the appearance of strange colors and the gradual degradation of reliability as the program does more off-screen drawing. Building an off-screen graphics environment out of a CGrafPort, GDevice, and PixMap or by using GWorlds, combined with an understanding of how Color QuickDraw uses off-screen graphics environments, helps get rid of these problems. Hopefully, this Note helps you understand these things so that you can get better programs out the door faster.
  3243. Further Reference:
  3244. •    Apple Computer, Inc., Inside Macintosh Volume I, Addison-Wesley, Reading, MA, 1985
  3245. •    Apple Computer, Inc., Inside Macintosh Volume V, Addison-Wesley, Reading, MA, 1988.
  3246. •    Apple Computer, Inc., Inside Macintosh Volume VI, Addison-Wesley, Reading, MA, 1991.
  3247. •    Knaster, S., Macintosh Programming Secrets, Addison-Wesley, Reading, MA, 1988.
  3248. •    Leak, B., “Realistic Color For Real-World Applications,” develop, January 1990, 4-21.
  3249. •    Ortiz, G., “Braving Offscreen GWorlds,” develop, January 1990, 28-40.
  3250. •    Ortiz, G., “Deaccelerated _CopyBits & 8•24 GC QuickDraw,” Macintosh Technical Note #289, January 1991.
  3251. •    Ortiz, G., “Macintosh Display Card 8•24 GC: The Naked Truth,”  develop, July 1990, 332-347.
  3252. •    Othmer, K., “QuickDraw’s CopyBits Procedure: Better Than Ever in System 7.0,” develop, Spring 1991, 23-42.
  3253. •    Tanaka, F., “Of Time and Space and _CopyBits,” Macintosh Technical Note #277, June 1990.
  3254. •    Zap, J., F. Tanaka, J. Friedlander, and G. Jernigan, “Drawing Into an Off-Screen Bitmap,” Macintosh Technical Note #41, June 1990.
  3255. NuBus is a trademark of Texas Instruments.
  3256.  
  3257. QD 14 - QuickDraw’s Internal Picture Definition
  3258. QuickDraw    
  3259. Revised by:    Rick Blair    November 1986
  3260.             March 1988
  3261. Written by:    Ginger Jenigan    April 1985
  3262. This technical note describes the internal format of the QuickDraw picture data structure. This revision corrects some errors in the opcode descriptions and provides some examples.
  3263. This technical note describes the internal definition of the QuickDraw picture. The information given here only applies to QuickDraw picture format version 1.0 (which is always created by Macintoshes without Color QuickDraw). Picture format version 2.0 is documented in the Color QuickDraw chapter of Inside Macintosh. This information should not be used to write your own picture bottleneck procedures; if we add new objects to the picture definition, your program will not be able to operate on pictures created using standard QuickDraw. Your program will not know the size of the new objects and will, therefore, not be able to proceed past the new objects. (What this ultimately means is that you can’t process a new picture with an old bottleneck proc.)
  3264. Terms
  3265. An opcode is a number that DrawPicture uses to determine what object to draw or what mode to change for subsequent drawing. The following list gives the opcode, the name of the object (or mode), the associated data, and the total size of the opcode and data. To better interpret the sizes, please refer to page I-91 of the Using Assembly Language chapter of Inside Macintosh. For types not described there, here is a quick list:
  3266.     opcode    byte
  3267.     mode        word
  3268.     point        4 bytes
  3269.     0..255    byte
  3270.     –128..127    signed byte
  3271.     rect        8 bytes
  3272.     poly        10+ bytes (starts with word size for poly (incl. size word)
  3273.     region        10+ bytes (starts with word size for region (incl. size word)
  3274.     fixed point    long
  3275.     pattern    8 bytes
  3276.     rowbytes    word (always even)
  3277.     bit data    rowbytes * (bounds.bottom - bounds.top) bytes
  3278. Each picture definition begins with a picsize (word), then a picframe (rect), and then the picture definition, which consists of a combination of the following opcodes:
  3279. Opcode    Name    Additional Data    Total Size (bytes)
  3280. 00    NOP    none    1
  3281. 01    clipRgn    rgn    1+rgn
  3282. 02    bkPat    pattern    9
  3283. 03    txFont    font (word)    3
  3284. 04    txFace    face (byte)    2
  3285. 05     txMode    mode (word)    3
  3286. 06    spExtra    extra (fixed point)    5
  3287. 07    pnSize    pnSize (point)    5
  3288. 08    pnMode    mode (word)    3
  3289. 09    pnPat    pattern    9
  3290. 0A    thePat    pattern    9
  3291. 0B    ovSize    point    5
  3292. 0C    origin    dh, dv (words)    5
  3293. 0D    txSize    size (word)    3
  3294. 0E    fgColor    color (long)    5
  3295. 0F    bkColor    color (long)    5
  3296. 10    txRatio    numer (point), denom (point)    9
  3297. 11    picVersion    version (byte)    2
  3298. 20     line    pnLoc ( point ), newPt ( point )    9
  3299. 21    line from    newPt ( point )    5
  3300. 22    short line    pnLoc ( point ); dh, dv (-128..127)    7
  3301. 23    short line from    dh, dv (-128..127)    3
  3302. 28     long text    txLoc ( point ), count (0..255), text    6+text
  3303. 29    DH text    dh (0..255), count (0..255), text    3+text
  3304. 2A    DV text    dv (0..255), count (0..255), text    3+text
  3305. 2B    DHDV text    dh, dv (0..255), count (0..255), text    4+text
  3306. 30     frameRect    rect    9
  3307. 31    paintRect     rect    9
  3308. 32    eraseRect     rect    9
  3309. 33    invertRect     rect    9
  3310. 34    fillRect     rect    9
  3311. 38     frameSameRect    rect    1
  3312. 39    paintSameRect     rect    1
  3313. 3A    eraseSameRect     rect    1
  3314. 3B    invertSameRect     rect    1
  3315. 3C    fillSameRect     rect    1
  3316. 40     frameRRect    rect ( ovalwidth, height; see 1, below )    9
  3317. 41    paintRRect     rect ( ovalwidth, height; see 1, below )    9
  3318. 42    eraseRRect     rect ( ovalwidth, height; see 1, below )    9
  3319. 43    invertRRect     rect ( ovalwidth, height; see 1, below )    9
  3320. 44    fillRRect     rect ( ovalwidth, height; see 1, below )    9
  3321. 48     frameSameRRect rect    1
  3322. 49    paintSameRRect  rect    1
  3323. Opcode    Name    Additional Data    Total Size (bytes)
  3324. 4A    eraseSameRRect     rect    1
  3325. 4B    invertSameRRect     rect    1
  3326. 4C    fillSameRRect     rect    1
  3327. 50     frameOval    rect    9
  3328. 51    paintOval     rect    9
  3329. 52    eraseOval    rect    9
  3330. 53    invertOval     rect    9
  3331. 54    fillOval     rect    9
  3332. 58     frameSameOval    rect    1
  3333. 59    paintSameOval     rect    1
  3334. 5A    eraseSameOval     rect    1
  3335. 5B    invertSameOval    rect    1
  3336. 5C    fillSameOval     rect    1
  3337. 60     frameArc    rect, startAngle, arcAngle    13
  3338. 61    paintArc     rect, startAngle, arcAngle    13
  3339. 62    eraseArc    rect, startAngle, arcAngle    13
  3340. 63    invertArc     rect, startAngle, arcAngle    13
  3341. 64    fillArc     rect, startAngle, arcAngle    13
  3342. 68     frameSameArc    startAngle, arcAngle    5
  3343. 69    paintSameArc     startAngle, arcAngle    5
  3344. 6A    eraseSameArc     startAngle, arcAngle    5
  3345. 6B    invertSameArc    startAngle, arcAngle    5
  3346. 6C    fillSameArc     startAngle, arcAngle    5
  3347. 70    framePoly    poly    1+poly
  3348. 71    paintPoly    poly    1+poly
  3349. 72    erasePoly     poly    1+poly
  3350. 73    invertPoly     poly    1+poly
  3351. 74    fillPoly     poly    1+poly
  3352.     
  3353. 78    frameSamePoly     (not yet implemented—same as 70, etc.)    1
  3354. 79    paintSamePoly     (not yet implemented)    1
  3355. 7A    eraseSamePoly     (not yet implemented)    1
  3356. 7B    invertSamePoly    (not yet implemented)    1
  3357. 7C    fillSamePoly    (not yet implemented)    1
  3358. 80    frameRgn    rgn    1+rgn
  3359. 81    paintRgn    rgn    1+rgn
  3360. 82    eraseRgn     rgn    1+rgn
  3361. 83    invertRgn     rgn    1+rgn
  3362. 84    fillRgn     rgn    1+rgn
  3363. 88    frameSameRgn     (not yet implemented—same as 80, etc.)    1
  3364. 89    paintSameRgn     (not yet implemented)    1
  3365. 8A    eraseSameRgn     (not yet implemented)    1
  3366. 8B    invertSameRgn    (not yet implemented)    1
  3367. 8C    fillSameRgn    (not yet implemented)    1 
  3368. 90    BitsRect    rowBytes, bounds, srcRect, dstRect, mode,    29+unpacked
  3369.         unpacked bitData     bitData
  3370. Opcode    Name    Additional Data    Total Size (bytes)
  3371. 91    BitsRgn    rowBytes, bounds, srcRect, dstRect, mode,    29+rgn+
  3372.         maskRgn, unpacked bitData    bitData
  3373. 98    PackBitsRect    rowBytes, bounds, srcRect, dstRect, mode,    29+packed
  3374.         packed bitData for each row    bitData
  3375. 99    PackBitsRgn    rowBytes, bounds, srcRect, dstRect, mode,    29+rgn+
  3376.         maskRgn, packed bitData for each row    packed bitData
  3377. A0    shortComment    kind(word)    3
  3378. A1    longComment    kind(word), size(word), data    5+data
  3379. FF    EndOfPicture    none    1
  3380. Notes
  3381. Rounded-corner rectangles use the setting of the ovSize point (see opcode $0B, above).
  3382. OpenPicture and DrawPicture set up a default set of port characteristics when they start. When drawing occurs, if the user’s settings don’t match the defaults, mode opcodes are generated. This is why there is usually a clipRgn code after the picVersion: the default clip region is an empty rectangle.
  3383. The only savings that the “same” opcodes achieve under the current implementation is for rectangles. DrawPicture keeps track of the last rectangle used and if a “same” opcode is encountered that requests a rectangle, the last rect. will be used (and no rectangle will appear in the opcode’s data).
  3384. This last section contains some Pascal program fragments that generate pictures. Each section starts out with the picture itself (yes, they’re dull) followed by the code to create and draw it, and concludes with a commented hex dump of the picture.
  3385.     {variables used in all examples}
  3386.     VAR
  3387.         err:     OSErr;
  3388.         ph:      PicHandle;
  3389.         h:       Handle;
  3390.         r:       Rect;
  3391.         smallr:  Rect;
  3392.         orgr:    Rect;
  3393.         pstate:  PenState; {are they in the Rose Bowl, or the state pen?}
  3394. I.    {Rounded-corner rectangle}
  3395.     SetRect(r, 20, 10, 120, 175);
  3396.     ClipRect(myWindow^.portRect);
  3397.     ph := OpenPicture(r);
  3398.     FrameRoundRect (r, 5, 4); {r,width,height}
  3399.     ClosePicture;
  3400.     DrawPicture(ph, r);
  3401. 'PICT' (1)  0026 {size}  000A 0014 00AF 0078 {picFrame}
  3402.     1101 {version 1}  01 000A 0000 0000 00FA 0190 {clipRgn — 10 byte region}
  3403.     0B 0004 0005 {ovSize point}  40 000A 0014 00AF 0078 {frameRRect
  3404.     rectangle}
  3405.     FF {fin} 
  3406. __________________________________________________________________________________________
  3407. II.    {Overpainted arc}
  3408.     GetPenState(pstate); {save}
  3409.     SetRect(r, 20, 10, 120, 175);
  3410.     ClipRect(myWindow^.portRect);
  3411.     ph := OpenPicture(r);
  3412.     PaintArc(r, 3, 45); {r,startangle,endangle}
  3413.     PenPat(gray);
  3414.     PenMode(patXor); {turn the black to gray}
  3415.     PaintArc(r, 3, 45); {r,startangle,endangle}
  3416.     ClosePicture;
  3417.     SetPenState(pstate); {restore}
  3418.     DrawPicture(ph, r);
  3419. data 'PICT' (2)  0036 {size}  000A 0014 00AF 0078 {picFrame}
  3420.     1101 {version 1}  01 000A 0000 0000 00FA 0190 {clipRgn — 10 byte region}
  3421.     61 000A 0014 00AF 0078 0003 002D {paintArc rectangle,startangle,endangle}
  3422.     08 000A {pnMode patXor — note that the pnMode comes before the pnPat}
  3423.     09 AA55 AA55 AA55 AA55 {pnPat gray}
  3424.     69 0003 002D {paintSameArc startangle,endangle}
  3425.     FF {fin} 
  3426. III.    {CopyBits nopack, norgn, nowoman, nocry}
  3427.     GetPenState(pstate);
  3428.     SetRect(r, 20, 10, 120, 175);
  3429.     SetRect(smallr, 20, 10, 25, 15);
  3430.     SetRect(orgr, 0, 0, 30, 20);
  3431.     ClipRect(myWindow^.portRect);
  3432.     ph := OpenPicture(r);
  3433.     PaintRect(r);
  3434.     CopyBits (myWindow^.portBits, myWindow^.portBits,
  3435.                  smallr, orgr, notSrcXor, NIL); 
  3436.     {note: result BitMap is 8 bits wide instead of the 5 specified by     smallr}
  3437.     ClosePicture;
  3438.     SetPenState(pstate); {restore the port's original pen state}
  3439.     DrawPicture(ph, r);
  3440. data 'PICT' (3)  0048 {size}  000A 0014 00AF 0078 {picFrame}
  3441.     1101 {version 1}  01 000A 0000 0000 00FA 0190 {clipRgn — 10 byte region}
  3442.     31 000A 0014 00AF 0078 {paintRect rectangle}
  3443.     90 0002 000A 0014 000F 001C {BitsRect rowbytes bounds (note that bounds                     is wider than smallr)}
  3444.     000A 0014 000F 0019 {srcRect}
  3445.     0000 0000 0014 001E {dstRect}
  3446.     00 06 {mode=notSrcXor}
  3447.     0000 0000 0000 0000 0000 {5 rows of empty bitmap (we copied from a
  3448.                                 still-blank window)}
  3449.     FF {fin}
  3450. Further Reference:
  3451. •    QuickDraw
  3452. •    Color QuickDraw
  3453. •    Using Assembly Language
  3454. •    Technical Note #59—Pictures and Clip Regions
  3455. QD 15 - RowBytes Revealed II
  3456. QuickDraw    
  3457. Written by:Bill Guschwan    May 1993
  3458. This Technical Note discusses the maximum rowBytes value for a pixMap.
  3459. Topics
  3460.     • What is the largest value of rowBytes?
  3461.     • Why does it have a limit?
  3462.     • How do you increase the limit?
  3463.     
  3464. Introduction
  3465. This technical note concerns applications which create and read very large pixMaps. The rowBytes field defines the limits of the largest pixMap. For applications which use 32-Bit QuickDraw, this limit is well-defined: 0x3FFE. However, a few applications want to go beyond this limit, and under some extremely controlled situations, this limit can be extended to 0x7FFE. This note explains why the limit exists, and proposes a few difficult methods to exceed this limit. Along the way, proper parameter passing for CopyBits is discussed and a few debugging tips are thrown in.
  3466. Largest size of rowBytes of a pixMap
  3467. rowBytes is important because it defines the size of a pixMap. rowBytes had a largest size of 0x1FFE up through Color QuickDraw. The top three bits were reserved. 
  3468. Version 1.0 of 32-Bit QuickDraw extended that limit to 0x3FFE: only the top two bits are reserved. QuickDraw uses the two bits for identification purposes. The top bit distinguishes between a pixMap and a bitMap. If the top bit of rowBytes is set, then QuickDraw knows the structure is a pixMap. The second highest bit is used by CopyBits, CopyMask, CopyDeepMask, SeedCFill, and CalcCMask to distinguish between their bitMap parameters. The implications of this identification scheme are fully discussed below.
  3469. 3 Types of BitMap Parameters
  3470. CopyBits, CopyMask, CopyDeepMask, SeedCFill, and CalcCMask are routines which take bitMaps as their first two parameters. For historical and compatibility reasons, three types of parameters can be passed in: bitMap, pixMaps and the portBits field of a cGrafPort.
  3471. For the purposes of this note, I will focus on the CopyBits call, though my discussion will apply to the other four routines. The behavior of these five calls is identical for the bitMap parameters. 
  3472. The BitMap
  3473. The bitMap parameter is actually a pointer to a bitMap. In Pascal, the pointer is implicit, since a bitMap structure is greater than 4 bytes in size and the Pascal compiler creates a pointer for any data structure greater than 4 bytes.
  3474. In C:
  3475. pascal void CopyBits(const BitMap *srcBits,const BitMap *dstBits,const Rect
  3476.     *srcRect, const Rect *dstRect,short mode,RgnHandle maskRgn) = 0xA8EC; 
  3477. In Pascal:
  3478. PROCEDURE CopyBits(srcBits: BitMap;dstBits: BitMap;srcRect: Rect;dstRect: Rect;
  3479.     mode: INTEGER;maskRgn: RgnHandle);
  3480.     INLINE $A8EC;
  3481. The PixMap
  3482. With Color QuickDraw, CopyBits accepts pixMaps as BitMap parameters. This support, however, does not come without a cost. CopyBits needs a method to distinguish between the two parameters. As mentioned above, the top bit of rowBytes distinguishes between pixMaps and bitMaps. While this bit allows pixMaps to be passed in to CopyBits, the size of rowBytes is diminished. All design choices have trade-offs.
  3483. The portBits of a CGrafPort
  3484. In designing Color QuickDraw, certain rules were set up to provide compatibility with the new features. Here was one rule: you should be able to pass a portPixMap field to CopyBits just as you would pass a portBits field. Unfortunately, portPixMap is a handle whereas portBits is a BitMap. Tricky type-casting, however, allows one to pass in a cGrafPort's portPixMap field, as the following examples show. You must coerce the cGrafPtr in to a grafPtr in order to use the portBits field.
  3485. In C:
  3486.     CGrafPtr   colorPort;   /* Graphics environment for color off screen */
  3487.     GrafPtr    savedPort;   /* Pointer to the saved graphics environment */
  3488.     CopyBits(     &((GrafPtr)colorPort)->portBits, &savedPort->portBits,
  3489.                         &colorPort->portRect, &savedPort->portRect,
  3490.                         srcCopy, nil     );
  3491. In Pascal:
  3492.     colorPort:   CGrafPtr;   {Graphics environment for color off screen}
  3493.     savedPort:   GrafPtr;    {Pointer to the saved graphics environment}
  3494.     CopyBits(    GrafPtr(colorPort)^.portBits, savedPort^.portBits,
  3495.             colorPort^.portRect, savedPort^.portRect,
  3496.             srcCopy, NIL);
  3497. Typecasting is not the only trickery involved here. CopyBits is faced with a major headache if you think about it. PortPixMap is a handle, and the parameters of CopyBits expect a pointer to a pixMap. To solve this, CopyBits has a little algorithm in it which dereferences the pointer twice if you pass in a portBits. To identify the type of pointer it is getting, CopyBits looks at the top two bits of the rowBytes field. As mentioned above, the top bit distinguishes between a pixMap and a bitMap. The next bit tells CopyBits if the pixMap is part of a cGrafPort or not (see Fig. 1). If the two bits are set, then CopyBits knows it is being passed a pixMapHandle, and it will perform the dereference.
  3498. Figure 1. CopyBit's BitMap parameters
  3499. Figure 1. displays three types of CopyBit's BitMap parameters. Each points to a either a bitMap, pixMap, or the portPixMap field in a cGrafPort. After 4 bytes, the top two bits of the fifth byte identifies the pointer.
  3500. Why Large PixMaps Crash Apps
  3501. As you can see, the top two bits of rowBytes have specific functions. The highest bit distinguishes between bitMaps and pixMaps. The second highest bit identifies the type of BitMap parameter. If it is set, a dereference is applied; if not, nothing happens to the pixMap.  If your pixMap uses the second highest bit of rowBytes and you pass it into a QuickDraw application, it will think it is part of a cGrafPort, and will perform a handle dereference on your baseAddr. The first dereference will get to video memory, but the second dereference will be on whatever random video data happens to be there. Your application will land up in Never-Never land.
  3502. If you create pictures which can be redistributed, leave the top two bits of rowBytes alone. Below, I will identify one method of going around this limit, but it will only work in specific situations. If you read pictures, look below for reading pictures which go around this limit.
  3503. Identifying CGrafPorts and GWorlds in a Debugger
  3504. You'll notice in Figure 1 that the portVersion field of a cGrafPort coincides with the location of the rowBytes field of a grafPort. Remember, a cGrafPort has the same size as a grafPort. During debugging, you can use the same information which CopyBits uses to identify cGrafPorts.
  3505. If you use a grafPort template to display memory for an unknown grafPort, you can tell if it is a cGrafPort because the rowBytes will be equal to 0xC000. The 0xC corresponds to the two high bits being set in the portVersion field of a cGrafPort. Since these bits can not be set in a grafPort, you know you have a cGrafPort. In addition, if the bottom bit of the portVersion field is set, then it is a gWorld. Thus, if your rowBytes field has a value of 0xC001, then you know you have a gWorld.
  3506. Even or odd rowBytes?
  3507. Since the dawn of Macintosh, it has been said that rowBytes should be even because each row of a pixMap must contain an integral number of words. Actually, rowBytes has to be even because QuickDraw accesses bitmap data using word or long operands, and these generate address errors when it references an odd address on the 68000, which would happen if rowBytes is odd. The 68020 and later handle odd addresses fine, and so rowBytes can be odd. But, it is still recommended that rowBytes be even, because misaligned accesses incur a performance penalty.
  3508. Going Around The Limit Today
  3509. In the world today applications have a difficulty because they can either refuse to create pixMaps as big as users want or cause crashes by confusing CopyBits into dereferencing the base address of the pixMap if rowBytes exceeds the established limit of less than 0x4000. Some well-known image applications create such pixMaps with bad results. Reading large pixMaps causes the crash, but applications which create them are the ultimate culprit.
  3510. As far as a solution for the present, a possibility is to bypass the CopyBits dereferencing algorithm. You can call StdBits directly since it does not mind dealing with larger than legal rowBytes. The problem here is that the destination is implied and the application has to make sure that everything is alright. Also, if the destination spans multiple devices, the application has to divide the task , targeting each device at the time. See the DeviceLoop procedure in IM VI for ideas on this. 
  3511. A second possibility is to patch CopyBits in situations where you know it can only be fed pixMaps. DrawPicture time is one example. You need to patch right before DrawPicture because you know a picture will contain only pixMaps. That is, you know CopyBits will not be passed portBits. If rowBytes is too big, then the application could split the job, banding the image vertically until the resulting rowBytes values fall within range. After the DrawPicture call, you will need to unpatch.
  3512. Going Around The Limit Tomorrow
  3513. All this is known by engineering and some future directions are already being studied, for example it is possible that a next release of QuickDraw will support pixMap with a rowBytes constant value indicating that the real rowBytes is contained in the planeBytes field instead; I am sure you can immediately think of cases where this is also going to cause problems but we think that the problems are less important than the limitation being overcome.
  3514. Conclusion
  3515. The limitations of rowBytes is becoming an increasingly painful thing, applications can easily create pixMaps (and PICTs) that exceed the limit of 0x4000. It is possible for an application to patch CopyBits in order to work around this limitation but the application writer has to decide what is appropriate for each set of conditions. Thus, rowBytes has traditionally been said to have a maximum value of 0x3FFE. But, if your application avoids the use of CopyBits, CopyMask, and CopyDeepMask, then you can use a rowBytes value of 0x7FFF without harm. However, those situations are rare, and, for all practical matters, the limit of rowBytes is 0x3FFE.
  3516. Further Reference:
  3517. •    Inside Macintosh, Volume I, QuickDraw
  3518. •    Inside Macintosh, Volume V & VI, Color QuickDraw
  3519. •    d e v e l o p 1, "Realistic Color For Real-World Applications"
  3520. QD 16 - 8•24 GC QuickDraw and Deaccelerated CopyBits
  3521. QuickDraw    
  3522. Written by:    Guillermo A. Ortiz    February 1991
  3523. This Technical Note discusses conditions that may cause _CopyBits to slow down when QuickDraw acceleration is on via the Apple 8•24 GC Display Card.
  3524. Introduction
  3525. When a drawing call is issued, GC IPC (Interprocess Communication) takes control of the call and passes it to GC QuickDraw.  After the normal port set up (which involves caching the port parameters if this is the first drawing call after the port was set), GC QuickDraw returns control to the application through the IPC and performs, in parallel, the drawing to its own monitor as well as any other monitors that may be affected by  the operation.  The application then continues its execution, probably issuing more drawing calls that get executed in the same asynchronous manner.
  3526. The result of this mode of operation is improved performance, since the application gets control back immediately after issuing the call and the GC QuickDraw moves video data to its own video buffer as well as that of other cards in a more rapid manner by using block transfers and without requiring any action by the main processor.
  3527. _CopyBits Conforms To The Same Scheme, Except…
  3528. _CopyBits conforms to the same operational scheme, but there are some instances in which GC QuickDraw cannot perform the call in parallel; in this cases it is even possible to suffer a performance loss, since the whole call may have to be completed before control is given back to the application and GC QuickDraw has to make calls and access data across the NuBus™.
  3529. The situations that compromise GC QuickDraw parallel operation are as follows:
  3530. •    When the destination device has a SearchProc installed and the source color environment is different from the destination environment.
  3531.     QuickDraw calls a SearchProc whenever the source and destination have different depths and when two indexed pixel maps have different color tables, even though their depths may be identical.  When GC acceleration is enabled, these conditions cause the following two types of behavior, dependent upon the source pixel map:
  3532. •    If the source is an indexed pixel map, then GC QuickDraw executes the part of the setup that involves calling the SearchProc, returns control to the main processor, then completes the call in parallel.  The act of calling the SearchProc before returning control makes the call slower than when no SearchProc is involved, since parallel operation does not occur throughout the whole call.
  3533. •    If the source is a direct RGB pixel map, then GC QuickDraw has to call the SearchProc for every pixel that is drawn, and the application does not regain control until after the call to _CopyBits has been completed.
  3534. •    When the source or destination is offscreen and not created using a GWorld.
  3535.     GC QuickDraw has no way to detect when an application is going to manipulate a pixel map it has created in memory, so if it has to draw to or copy from such a PixMap, GC QuickDraw has to complete the operation before returning control to the application.
  3536.     This behavior is contrary to the case when using a GWorld for offscreen environments, since in the case of a GWorld, GC QuickDraw is alerted by the call to _GetPixBaseAddr that the application is getting ready to directly change the pixels.  This is the reason why it is so important that applications call _GetPixBaseAddr every time they are about to manipulate a GWorld pixel map directly.
  3537. •    When the source PixMap has a color table that uses indexes that refer to a palette.
  3538.     QuickDraw now allows a color table to have indexes that point to entries in the palette associated with the destination window; when bit 14 in the ctFlags field is set, the value fields in the color table are treated as palette entries.  When such a PixMap is the source for _CopyBits, then GC QuickDraw has to make a number of calls to the Palette Manager as part of the setup before returning control and completing the call.
  3539.     This case is similar to that of a indexed pixel map when a SearchProc is involved; therefore, it only implies a partial loss of parallelism; it is good to keep in mind that this case can only occur when the source PixMap is indexed.
  3540. Further Reference:
  3541. •    Inside Macintosh, Volumes V & VI, Color QuickDraw
  3542. •    d e v e l o p, “Macintosh Display Card 8•24 GC:  The Naked Truth,” July 1990.
  3543. •    Technical Note #275, 32-Bit QuickDraw:  Version 1.2 Features
  3544. •    Developer Notes for the Macintosh Display Cards 4•8, 8•24 and 8•24 GC (APDA, M085TLL/A)
  3545. NuBus is a trademark of Texas Instruments.
  3546. QD 17 - Drawing Icons
  3547. QuickDraw    
  3548. Written by:    Jim Friedlander    October 1985
  3549. Using resources of type ICON allows drawing of icons in srcOr mode.  Using resources of type ICN# allows for more variety when drawing icons.
  3550. There are two different kinds of resources that contain icons: ICON and ICN#. An ICON is a 32 by 32 bit image of an icon and can be drawn using the following Toolbox Utilities calls:
  3551.     MyIconHndl:= GetIcon(iconID);
  3552.     PlotIcon(destRect,iconID);
  3553. While very convenient, this method only allows the drawing of icons in SrcOr mode (as in the MiniFinder). The Finder uses resources of type ICN# to draw icons on the desktop. Because the Finder uses ICN#s, it can draw icons in a variety of ways.
  3554. An ICN# resource is a list of 32 by 32 bit images that are grouped together. Common convention has been to group two 32 by 32 bit images together in each ICN#. The first image is the actual icon, the second image is the mask for the icon. To get a handle to an ICN#, we would use something like this:
  3555. TYPE
  3556.     iListHndl    = ^iListPtr;
  3557.     iListPtr     = ^iListStruct;
  3558.     iListStruct  = record
  3559.         icon : packed array[0..31] of Longint;
  3560.         mask : packed array[0..31] of Longint;
  3561.     End; {iListStruct}
  3562. VAR
  3563.     myILHndl      : iListHndl;            {handle to an ICN#}
  3564.     iBitMap       : BitMap;          {BitMap for the icon}
  3565.     mBitMap       : BitMap;          {BitMap for the mask}
  3566.     MyILHndl:= iListHndl(GetResource('ICN#',iconID));          
  3567.     if MyILHndl = NIL then HandleError; 
  3568.         {and exit or whatever is appropriate}
  3569. Once we have a handle to the icons, we need to set up two bitMaps that we will be using later in CopyBits: 
  3570.         SetRect(icnRect,0,0,32,32);                { define the icon's 'bounds'}
  3571.     With iBitMap do Begin
  3572.          baseAddr:= @MyILHndl^^.icon;    
  3573.          rowbytes:= 4;                            { 4 * 8 =32}
  3574.          bounds:= icnRect;
  3575.      End; {with}
  3576.       With mBitMap do Begin
  3577.          baseAddr:= @MyILHndl^^.mask;
  3578.          rowbytes:= 4;
  3579.          bounds:= icnRect;
  3580.       End; {with}
  3581. Icons can represent desktop objects that are either selected or not. Folder and volume icons can either be open or not. The object (or the volume it is on) can either be online or offline. The Finder draws icons using all permutations of open, selected and online:
  3582. Drawing icons as non-open is basically the same for online and offline volumes. We need to punch a hole in the desktop for the icon. This is analogous to punching a hole in dough with an irregular shaped cookie-cutter. We can then sprinkle jimmies* all over the cookie and they will only stick in the area that we punched out (the mask). We do this by copyBitsing the mask onto the desktop (whatever pattern) to our destRect. For non-open, non-selected icons: 
  3583. we use the SrcBic mode so that we punch a white hole:
  3584.     SetRect(destRect,left,top,left+32,top+32);
  3585.     CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL); 
  3586. Then we XOR in the icon:
  3587.      CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcXor,NIL);
  3588. That’s all there is to drawing an icon as non-open, non-selected. To draw the icon as non-open, selected:
  3589.  
  3590. we will OR in the mask, causing a mask-shaped BLACK hole to be punched in the desktop:
  3591.     CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcOr,NIL); 
  3592. Then, as before, we XOR in the icon:
  3593.     CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcXOr,NIL);
  3594. To draw icons as non-opened for offline volumes:
  3595. we need to do a little more work. We need to XOR a ltGray pattern into the boundsRect of the icon. We will then punch the hole, draw the icon and then XOR out the ltgray pattern that does not fall inside the mask. So, to draw the icon as offline, non-open, non-selected we would:
  3596.     GetPenState(OldPen);        {save the pen state so we can restore it}
  3597.     PenMode(patXor);
  3598.       PenPat(ltGray);
  3599.       PaintRect(destRect);        {paint a ltGray background for icon}
  3600.       CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL); {punch}
  3601.      PaintRect(destRect);{XOR out bits outside of the mask, leaving the mask} 
  3602.                 {filled with ltGray}
  3603.                                                 
  3604.                                            CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcOr,NIL);{ OR in }                                                                                   { the icon to the ltGray                                   mask}
  3605. SetPenState(OldPen);                           {restore the old pen state}
  3606. To draw the icon as offline, non-open, selected:
  3607. we would use a similar approach:
  3608.         GetPenState(OldPen);        { save the pen state so we can restore it}
  3609.     PenMode(patXor);
  3610.     PenPat(dkGray);        { the icon is selected, so we need dkGray }
  3611.       PaintRect(destRect);        { paint a dkGray background for icon }
  3612.     {punch a hole in the background}
  3613.       CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  3614.     PaintRect(destRect);        {XOR out bits outside of the mask, leaving
  3615.                      the mask filled with dkGray}
  3616.     {BIC the icon to the dkGray mask}
  3617.     CopyBits(iBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  3618.       SetPenState(OldPen);         {restore the old pen state}
  3619. Drawing the opened icons requires one less step. We don’’t have to CopyBits the icon in, we just use the mask. Online and offline icons are drawn the same way. To draw icons as open, selected:
  3620. we do the following:
  3621.         GetPenState(OldPen);        {save the pen state so we can restore it}
  3622.       PenMode(patXor);
  3623.       PenPat(dkGray);        { the icon is selected, so we need dkGray }
  3624.        PaintRect(destRect);        { paint a dkGray background for icon}
  3625.     {punch a hole in the background}
  3626.       CopyBits(mBitMap,thePort^.portBits,icnRect,destRect,SrcBic,NIL);
  3627.   
  3628.       PaintRect(destRect);      {XOR out bits outside of the mask, leaving 
  3629.                      the mask filled with dkGray}
  3630.       SetPenState(OldPen);        {restore the old pen state}
  3631. To draw icons as open, non-selected:
  3632. we just need to change one line from above. Instead of XORing with a dkGray pattern, we use a ltGray pattern:
  3633.       PenPat(ltGray);        {icon is non-selected, so we need ltGray}
  3634. These techniques will work on any background, window-white or desktop-gray and all patterns in between. Have fun.
  3635. * jimmies : little bits of chocolate
  3636. Further Reference:
  3637. •    QuickDraw
  3638. •    Toolbox Utilities
  3639. QD 18 - Drawing Icons the System 7 Way
  3640. QuickDraw    
  3641. Revised by:    Don Moccia and C.K. Haun <TR>    October 1992
  3642. Written by:    Jim Mensch and David Collins    October 1991
  3643. This Technical Note describes how to utilize the built-in System 7 icon drawing utility. Use this information to better conform to the System 7 visual human interface.
  3644. Changes since May 1992: In this Note, we replaced the C and Pascal interface files and corrected the related text. So much text was tweaked that change bars are used only on code changes. 
  3645. Introduction
  3646. With the introduction of System 7 for the Macintosh, Apple has defined a new look and feel for many screen elements that better utilize color. Among those redefined elements are the icons drawn by the Finder and other system components. Until now, Apple has not documented how to draw icons the way the Finder does in System 7.
  3647. This Technical Note discusses the icon toolkit calls that the Finder uses to draw and manipulate the screen icons. Two of the calls, PlotIconID and PlotCIconHandle, are the ones you will probably use the most since they simply deal with drawing single icons to the screen. Some parts of the toolbox require that an icon family handle be passed to them to allow the drawing of color icons. The icon toolkit provides calls that allow you to create, draw, and manipulate these handles.
  3648. The New 'ic' Type Resources
  3649. PlotIconID and PlotCIconHandle allow the use of standard CIcons as documented in Inside Macintosh Volume V. The PlotIconID call also permits the use of a new set of icon resources documented in Inside Macintosh Volume VI, Chapter 9. This new set is a collection of different icons, representing a single Finder object, into a family. Each member of the family has the same resource ID as the 'ICN#', and a resource type indicating the icon data it contains. Currently Apple has defined three sizes of icons and three bit depths for each size. The sizes are large (32 by 32 pixels), small (16 by 16 pixels), and mini (12 by 12 pixels). The bit depths are 1, 4, and 8. The actual resource types are defined as:
  3650. Large1BitMask    =    'ICN#';
  3651. Large4BitData    =    'icl4';
  3652. Large8BitData    =    'icl8';
  3653. Small1BitMask    =    'ics#';
  3654. Small4BitData    =    'ics4';
  3655. Small8BitData    =    'ics8';
  3656. Mini1BitMask     =    'icm#';
  3657. Mini4BitData     =    'icm4';
  3658. Mini8BitData     =    'icm8';
  3659. The 1-bit-per-pixel member of each size also contains the mask data for all icons of that size (yes, this means that all your icons of a certain size must have the same mask). A 1-bit-per-pixel member must exist for each icon size that PlotIconID uses. The icon size used is determined by the size of the destination rectangle. If the destination rectangle is greater than 16 pixels on a side then the large icon will be used. If the rectangle is 13–16 pixels on both sides, the small icon will be used. If it is 12 or less on each side, the mini-icon will be used. The bit depth is determined by the device of the grafPort you plot into at drawing time. Be sure to create a color grafPort when you want to use color icons.
  3660. Icon Families (or Suites and Caches As the Tool Set Refers to Them)
  3661. An icon family is simply a collection of icon handles that contain up to one image of each bit depth and size for a given icon. The family can be fully populated (every possible size or depth available), or it can have only those icons that exist or are needed. By using families, you remove the need to determine which size or depth of icon to use when drawing into a given rectangle. Several system routines, the Notification Manager for example, can take an icon family handle when an icon is requested. This permits them to use the proper color icons if available. In the case of a sparsely populated icon family, when the proper icon is not available, the icon toolkit will pick a substitute to produce the best results.
  3662. An icon cache is a family that also has a ProcPtr and a refCon. The main difference between a cache and a family is that the elements of the cache’s array are sparsely populated. When using an icon cache, the system either will use the entry in the icon family portion of the cache or, if the desired element is empty, it will call the procedure pointed to by the ProcPtr and request the data for the icon. The procedure should have this interface:
  3663. FUNCTION IconGetter(theType: ResType;
  3664.                     yourDataPtr: Ptr): Handle;
  3665. This function should return either the icon data to be drawn or NIL to signify that this entry in the icon cache does not exist. Icon caches can be used with all icon family calls. A few extra calls are also available to manipulate icon caches.
  3666. Drawing Modes or Transforms
  3667. In addition to various sizes and bit depths, icons can be drawn with different modes or transforms. Transforms are analogous to certain Finder states for the icons. For example, the transform that you would use to show an icon of a disk that has been ejected is ttOffline. Here is a list of the available transforms:
  3668. ttNone                =    $0;
  3669. ttDisabled            =    $1;
  3670. ttOffline             =    $2;
  3671. ttOpen                =    $3;
  3672. ttSelected            =    $4000;
  3673. ttSelectedDisabled    =    (ttSelected + ttDisabled);
  3674. ttSelectedOffline     =    (ttSelected + ttOffline);
  3675. ttSelectedOpen        =    (ttSelected + ttOpen);
  3676. The actual appearance of the icon drawn by each transform type may vary with future system software, so you should always use the transform that best fits the state it represents in your application. This way you will be consistent with future changes to the look and feel of regular system icons. Note the ttSelected transform can be added to any of the other transform types.
  3677. There are also transforms that use the Finder label colors to color the icon. To determine the proper label for a file’s icon, you can check bits 1–3 of the fdFlags field in the file’s Finder info. (See the Finder Interface chapter in Inside Macintosh Volume VI for more information). These bits contain a number from 0 to 7. Simply add the corresponding ttLabel value to the transform that you give the call. The label values are defined like this:
  3678. ttLabel1    =    $0100;
  3679. ttLabel2    =    $0200;
  3680. ttLabel3    =    $0300;
  3681. ttLabel4    =    $0400;
  3682. ttLabel5    =    $0500;
  3683. ttLabel6    =    $0600;
  3684. ttLabel7    =    $0700;
  3685. Alignment
  3686. Most icons do not fully fill their rectangle, and it is sometimes necessary to draw an icon relative to other data (like menu text). In these instances it is nice to be able to have the icon move in its rectangle so that it will be at a predictable location in the destination rectangle. When drawing an icon you can pass one of these standard alignments in the alignment parameter or you can add a vertical alignment to a horizontal alignment to create a composite alignment value.
  3687. atNone                =    $0;
  3688. atVerticalCenter      =    $1;
  3689. atTop                 =    $2;
  3690. atBottom              =    $3;
  3691. atHorizontalCenter    =    $4;
  3692. atAbsoluteCenter      =    (atVerticalCenter + atHorizontalCenter);
  3693. atCenterTop           =    (atTop + atHorizontalCenter);
  3694. atCenterBottom        =    (atBottom + atHorizontalCenter);
  3695. atLeft                =    $8;
  3696. atCenterLeft          =    (atVerticalCenter + atLeft);
  3697. atTopLeft             =    (atTop + atLeft);
  3698. atBottomLeft          =    (atBottom + atLeft);
  3699. atRight               =    $C;
  3700. atCenterRight         =    (atVerticalCenter + atRight);
  3701. atTopRight            =    (atTop + atRight);
  3702. atBottomRight         =    (atBottom + atRight);
  3703. And Now (Drum Roll Please) the Calls and What to Pass
  3704. Now that we have defined every major data type we can think of, here are the actual toolkit calls themselves. One word of caution: only the ForEachIconDo call protects the handle that is passed to it, so make your icon resources nonpurgeable.
  3705. Icon Family Calls
  3706. FUNCTION NewIconSuite(VAR theIconSuite: Handle): OSErr;
  3707. NewIconSuite returns an empty icon family handle with all members set to NIL.
  3708. FUNCTION AddIconToSuite(theIconData: Handle;
  3709.                         theSuite: Handle;
  3710.                         theType: ResType): OSErr;
  3711. This call will add the data in theIconData into the suite at the location reserved for theType of icon data. AddIconToSuite will replace any old data in that slot without disposing of it, so you may want to call GetIconFromSuite to obtain the old handle (if any) to dispose of it. This call will be used most often with the NewIconSuite call to fill the empty family after it’s created.
  3712. FUNCTION GetIconFromSuite(VAR theIconData: Handle;
  3713.                           theSuite: Handle;
  3714.                           theType: ResType): OSErr;
  3715. This call will return a handle to the pixel data of the family member of theSuite specified by theType. If you intend to dispose of this handle, be sure to call AddIconToSuite with a NIL handle to zero out the family entry.
  3716. FUNCTION ForEachIconDo(theSuite: Handle;
  3717.                        selector: IconSelectorValue;
  3718.                        action: IconAction;
  3719.                        yourDataPtr: Ptr): OSErr;
  3720. This routine will call your IconAction procedure (see below) for each icon in the family specified by selector and theSuite. The selector parameter is a bit-level flag that specifies which family members to operate on; they can be added together to create composite selectors that work on several different family members. The values for selector are:
  3721. svLarge1Bit        =    $00000001;
  3722. svLarge4Bit        =    $00000002;
  3723. svLarge8Bit        =    $00000004;
  3724. svSmall1Bit        =    $00000100;
  3725. svSmall4Bit        =    $00000200;
  3726. svSmall8Bit        =    $00000400;
  3727. svMini1Bit         =    $00010000;
  3728. svMini4Bit         =    $00020000;
  3729. svMini8Bit         =    $00040000;
  3730. svAllLargeData     =    $000000FF;
  3731. svAllSmallData     =    $0000FF00;
  3732. svAllMiniData      =    $00FF0000;
  3733. svAll1BitData      =    (svLarge1Bit + svSmall1Bit + svMini1Bit);
  3734. svAll4BitData      =    (svLarge4Bit + svSmall4Bit + svMini4Bit);
  3735. svAll8BitData      =    (svLarge8Bit + svSmall8Bit + svMini8Bit);
  3736. svAllAvailableD    =    $FFFFFFFF;
  3737. The action procedure that gets called for each icon type selected for the family is a Pascal type function with the following interface:
  3738. FUNCTION IconAction(theType: ResType;
  3739.                     VAR theIcon: Handle;
  3740.                     yourDataPtr: Ptr): OSErr;
  3741. The parameter theIcon is passed by reference here so that your routine can modify the contents of the suite directly. The yourDataPtr parameter is the value passed when you called ForEachIconDo. It allows you to easily communicate with your application. The action procedure returns an OSErr. If any value other than noErr is returned, ForEachIconDo will stop processing immediately and return the error passed. (Note: This implies that the icons selected may only be partially operated on. There is no guaranteed order in which the icons get operated on.)
  3742. FUNCTION GetIconSuite(VAR theIconSuite: Handle;
  3743.                       theResID: INTEGER;
  3744.                       selector: IconSelectorValue): OSErr;
  3745. GetIconSuite will create a new icon family and fill it from the current resource chain with the icons of resource ID theResID and types indicated by selector. This is the call you will probably use most often to create an icon family. Note that if you SetResLoad(False) before making this call, the suite will be filled with unloaded resource handles.
  3746. FUNCTION PlotIconSuite(theRect: Rect;
  3747.                        align: IconAlignmentType;
  3748.                        transform: IconTransformType;
  3749.                        theIconSuite: Handle): OSErr;
  3750. This call renders the proper icon image from the passed icon family based on the bit depth of 
  3751. the display you are using and the rectangle that you have passed. The parameters align and transform are applied to the icon selected for drawing and then the icon is plotted into the current grafPort. PlotIconSuite chooses the appropriate icon based primarily on size. Once the proper icon size is determined (based on the destination rectangle), the present member of that size with the deepest bit depth that the current device can use is selected. A size category is considered present if the black-and-white member (with mask), 'ICN#', 'ics#', or 'icm#', is present. PlotIconSuite can be used for both picture accumulation and printing.
  3752. FUNCTION DisposeIconSuite(theIconSuite: Handle;
  3753.                           disposeData: BOOLEAN): OSErr;
  3754. This call disposes the icon family handle itself. In addition, if disposeData is true, any of the icon data handles that do not belong to a resource fork will also be disposed.
  3755. FUNCTION SetSuiteLabel(theSuite: Handle; theLabel: INTEGER): OSErr;
  3756. This call allows you to specify a label to draw an icon of this suite when no label is specified in PlotIconSuite. This is used primarily to ensure that a family passed to a system routine gets drawn with the proper label. The default label can be overridden by specifying a label in PlotIconSuite.
  3757. FUNCTION GetSuiteLabel(theSuite: Handle): INTEGER;
  3758. GetSuiteLabel returns the label previously set with SetSuiteLabel.
  3759. Icon Cache Calls
  3760. In addition to the icon family calls, icon caches have these additional calls: 
  3761. FUNCTION MakeIconCache(VAR theHandle: Handle;
  3762.                        makeIcon: IconGetter;
  3763.                        yourDataPtr: UNIV Ptr): OSErr;
  3764. This call creates an empty icon cache similar to NewIconSuite, and associates the additional icon loading procedure and data value with the family.
  3765. FUNCTION LoadIconCache(theRect: Rect;
  3766.                        align: IconAlignmentType;
  3767.                        transform: IconTransformType;
  3768.                        theIconCache: Handle): OSErr;
  3769. This call allows preflight loading of certain elements of your icon cache. This is handy if you suspect that certain drawing operations may occur at a time not convenient for loading your icon data (e.g., when your resource fork might not be in open chain). LoadIconCache takes the same parameters as PlotIconSuite and uses the same criteria to select the icon to load. The grafPort must be set properly before making this call since it is one of the criteria for determining the icon to load.
  3770. The following four calls are provided to change theData or theProc associated with an icon cache:
  3771. FUNCTION GetIconCacheData(theCache: Handle; 
  3772.                           VAR theData: Ptr): OSErr;
  3773. FUNCTION SetIconCacheData(theCache: Handle; 
  3774.                           theData: Ptr): OSErr;
  3775. FUNCTION GetIconCacheProc(theCache: Handle; 
  3776.                           VAR theProc: IconGetter): OSErr;
  3777. FUNCTION SetIconCacheProc(theCache: Handle; 
  3778.                           theProc: IconGetter): OSErr;
  3779. Plotting Icons Not Part of a Suite
  3780. The next calls are grouped because they are similar. They let you plot an icon to the screen without your creating an icon suite. They are also good if you have a 'cicn' instead of an icon family.
  3781. FUNCTION PlotIconID(theRect: Rect;
  3782.                     align: IconAlignmentType;
  3783.                     transform: IconTransformType;
  3784.                     theResID: INTEGER): OSErr;
  3785. FUNCTION PlotCIconHandle(theRect: Rect;
  3786.                          align: IconAlignmentType;
  3787.                          transform: IconTransformType;
  3788.                          theCIcon: CIconHandle): OSErr;
  3789. FUNCTION PlotIconMethod(theRect: Rect;
  3790.                         align: IconAlignmentType;
  3791.                         transform: IconTransformType;
  3792.                         theMethod: IconGetter;
  3793.                         yourDataPtr: UNIV Ptr): OSErr;
  3794. FUNCTION PlotIconHandle(theRect: Rect;
  3795.                         align: IconAlignmentType;
  3796.                         transform: IconTransformType;
  3797.                         theIcon: Handle): OSErr;
  3798. FUNCTION PlotSICNHandle(theRect: Rect;
  3799.                         align: IconAlignmentType;
  3800.                         transform: IconTransformType;
  3801.                         theSICN: Handle): OSErr;
  3802. All these routines share the following parameters: theRect is the destination rectangle to draw the indicated icon into; align is the alignment method to use if the icon does not fit the rectangle given; transform indicates the desired appearance of the icon on the screen.
  3803. In PlotIconID, the parameter theResID is the resource ID of the family of 'ic' type resources to use. If the correct bit depth or the size required is not defined, the closest-fitting one will be used.
  3804. The PlotCIconHandle parameter theCIcon is a handle that you get to a standard QuickDraw color icon. Unlike PlotCIcon, PlotCIconHandle does not honor the current foreground and background colors. Call GetCIcon to load the icon. Dispose of it when you are done, since they can take up quite a bit of memory.
  3805. PlotIconMethod calls your IconGetter procedure, discussed earlier, to check for the existence of icon data. 
  3806. PlotIconHandle will plot the data from an 'ICN#' or 'ICON' resource from its handle. It is a new version of PlotIcon.
  3807. PlotSICNHandle plots the data of a 'SICN' resource from its handle. Only 'SICN' resources with a single member, or one in which the second member is a mask for the first, will plot correctly.
  3808. All the functions return an error code if things did not go well with the drawing or, in the case of the PlotIconID call, if the indicated icon family could not be used.
  3809. Miscellaneous Calls
  3810. FUNCTION GetLabel(labelNumber: INTEGER;
  3811.                   VAR labelColor: RGBColor;
  3812.                   VAR labelString: Str255): OSErr;
  3813. This call returns the actual color and string used in the label menu of the Finder and the label’s Control Panel. This information is provided in case you wish to include the label text or color when displaying a file’s icon in your application.
  3814. FUNCTION IconSuiteToRgn(theRgn: RgnHandle;
  3815.                         iconRect: Rect;
  3816.                         align: IconAlignmentType;
  3817.                         theIconSuite: Handle): OSErr;
  3818. FUNCTION IconIDToRgn(theRgn: RgnHandle;
  3819.                      iconRect: Rect;
  3820.                      align: IconAlignmentType;
  3821.                      iconID: INTEGER): OSErr;
  3822. FUNCTION IconMethodToRgn(theRgn: RgnHandle;
  3823.                          iconRect: Rect;
  3824.                          align: IconAlignmentType;
  3825.                          theMethod: IconGetter;
  3826.                          yourDataPtr: Ptr): OSErr;
  3827. These routines will create a region from the mask of the icon selected by the iconRect and align values passed. They will allow you to do accurate hit testing and outline dragging of an icon in your application. The RgnHandle must have been previously allocated before you make this call.
  3828. FUNCTION RectInIconSuite(testRect: Rect;
  3829.                          iconRect: Rect;
  3830.                          align: IconAlignmentType;
  3831.                          theIconSuite: Handle): BOOLEAN;
  3832. FUNCTION RectInIconID(testRect: Rect;
  3833.                       iconRect: Rect;
  3834.                       align: IconAlignmentType;
  3835.                       iconID: INTEGER): BOOLEAN;
  3836. FUNCTION RectInIconMethod(testRect: Rect;
  3837.                           iconRect: Rect;
  3838.                           align: IconAlignmentType;
  3839.                           theMethod: IconGetter;
  3840.                           yourDataPtr: Ptr): BOOLEAN;
  3841. FUNCTION PtInIconSuite(testPt: Point;
  3842.                        iconRect: Rect;
  3843.                        align: IconAlignmentType;
  3844.                        theIconSuite: Handle): BOOLEAN;
  3845. FUNCTION PtInIconID(testPt: Point;
  3846.                     iconRect: Rect;
  3847.                     align: IconAlignmentType;
  3848.                     iconID: INTEGER): BOOLEAN;
  3849. FUNCTION PtInIconMethod(testPt: Point;
  3850.                         iconRect: Rect;
  3851.                         align: IconAlignmentType;
  3852.                         theMethod: IconGetter;
  3853.                         yourDataPtr: Ptr): BOOLEAN;
  3854. These calls hit test the passed Point or Rect against the icon indicated. The parameters iconRect and align, and the grafPort should be the same as when the icon was last drawn. The functions return true if the point is in the icon mask or if the rectangle intersects the icon mask.
  3855. Error Codes
  3856. The Icon Utilities will pass back any errors encountered during execution, so you can expect to see Memory Manager, Resource Manager, and other normal errors.
  3857. There is one error code defined specifically for the Icon Utilities routines that may be returned by the Icon plotting routines.
  3858. { Pascal }
  3859. CONST
  3860.     noMaskFound = -1000;
  3861. END;
  3862. /* C */
  3863. #define noMaskFound    -1000
  3864. This error will be returned if the Icon Utilities package could not find or create a mask for the icon family.  The Icon Utilities will use the correct mask for each icon size, if one is available.  If no mask for a specific size is available, a mask will be created from any mask in the family, but if there are no 1 bit images and no mask in the family, plotting calls will fail with this error.
  3865. Type(def)s and Glue for Pascal and C
  3866. The Pascal and C interfaces are provided here to copy and paste since the current MPW standard interface files do not contain the glue for these calls. Electronic versions of this note are on AppleLink (Developer Support: Developer Services: Technical Documentation: Macintosh Technical Notes: Imaging: Graphics: Icon Drawing in 7.sit (Stuffit)) and the Developer CD (Technical Documentation: Macintosh Technical Notes: Imaging: Graphics: Icon Drawing in 7).
  3867. MPW C, Pascal, and Assembler files also have been submitted to AppleLink and the Developer CD, but their paths were not known when this note was written.
  3868. { Pascal Types }
  3869. IconAction         =  ProcPtr;  {FUNCTION IconAction(theType: ResType;
  3870.                                                      VAR theIcon: Handle;
  3871.                                                      yourDataPtr: Ptr): OSErr;}
  3872. IconGetter         =  ProcPtr;  {FUNCTION IconGetter(theType: ResType;
  3873.                                                      yourDataPtr: Ptr): Handle;}
  3874. IconSelectorValue  =  LONGINT;
  3875. IconAlignmentType  =  INTEGER;
  3876. IconTransformType  =  INTEGER;
  3877. { Pascal Glue }
  3878. FUNCTION PlotIconID(theRect: Rect; align: IconAlignmentType; transform: IconTransformType;
  3879.                     theResID: INTEGER): OSErr;
  3880.          INLINE  $303C, $0500, $ABC9;
  3881. FUNCTION NewIconSuite(VAR theIconSuite: Handle): OSErr;
  3882.          INLINE  $303C, $0207, $ABC9;
  3883. FUNCTION AddIconToSuite(theIconData: Handle; theSuite: Handle; theType: ResType): OSErr;
  3884.          INLINE  $303C, $0608, $ABC9;
  3885. FUNCTION GetIconFromSuite(VAR theIconData: Handle; theSuite: Handle; theType: ResType): OSErr;
  3886.          INLINE  $303C, $0609, $ABC9;
  3887. FUNCTION ForEachIconDo(theSuite: Handle; selector: IconSelectorValue; action: IconAction;
  3888.                        yourDataPtr: Ptr): OSErr;
  3889.          INLINE  $303C, $060A, $ABC9;
  3890. FUNCTION GetIconSuite(VAR theIconSuite: Handle; theResID: INTEGER;
  3891.                       selector: IconSelectorValue): OSErr;
  3892.          INLINE  $303C, $0501, $ABC9;
  3893. FUNCTION DisposeIconSuite(theIconSuite: Handle; disposeData: BOOLEAN): OSErr;
  3894.          INLINE  $303C, $0302, $ABC9;
  3895. FUNCTION PlotIconSuite(theRect: Rect; align: IconAlignmentType; transform: IconTransformType;
  3896.                        theIconSuite: Handle): OSErr;
  3897.         INLINE  $303C, $0603, $ABC9;
  3898. FUNCTION MakeIconCache(VAR theHandle: Handle; makeIcon: IconGetter;
  3899.                        yourDataPtr: UNIV Ptr): OSErr;
  3900.          INLINE  $303C, $0604, $ABC9;
  3901. FUNCTION LoadIconCache(theRect: Rect; align: IconAlignmentType; transform: IconTransformType;
  3902.                        theIconCache: Handle): OSErr;
  3903.          INLINE  $303C, $0606, $ABC9;
  3904. FUNCTION PlotIconMethod(theRect: Rect; align: IconAlignmentType;
  3905.                         transform: IconTransformType; theMethod: IconGetter;
  3906.                         yourDataPtr: UNIV Ptr): OSErr; 
  3907.          INLINE  $303C, $0805, $ABC9;
  3908. FUNCTION GetLabel(labelNumber: INTEGER; VAR labelColor: RGBColor;
  3909.                   VAR labelString: Str255): OSErr;
  3910.          INLINE  $303C, $050B, $ABC9;
  3911. FUNCTION PtInIconID(testPt: Point; iconRect: Rect; align: IconAlignmentType;
  3912.                     iconID: INTEGER): BOOLEAN;
  3913.          INLINE  $303C, $060D, $ABC9;
  3914. FUNCTION PtInIconSuite(testPt: Point; iconRect: Rect; align: IconAlignmentType;
  3915.                        theIconSuite: Handle): BOOLEAN;
  3916.          INLINE  $303C, $070E, $ABC9;
  3917. FUNCTION PtInIconMethod(testPt: Point; iconRect: Rect; align: IconAlignmentType;
  3918.                         theMethod: IconGetter; yourDataPtr: Ptr): BOOLEAN;
  3919.          INLINE  $303C, $090F, $ABC9;
  3920. FUNCTION RectInIconID(testRect: Rect; iconRect: Rect; align: IconAlignmentType;
  3921.                       iconID: INTEGER): BOOLEAN;
  3922.          INLINE  $303C, $0610, $ABC9;
  3923. FUNCTION RectInIconSuite(testRect: Rect; iconRect: Rect; align: IconAlignmentType;
  3924.                          theIconSuite: Handle): BOOLEAN;
  3925.          INLINE  $303C, $0711, $ABC9;
  3926. FUNCTION RectInIconMethod(testRect: Rect; iconRect: Rect; align: IconAlignmentType;
  3927.                           theMethod: IconGetter; yourDataPtr: Ptr): BOOLEAN;
  3928.          INLINE  $303C, $0912, $ABC9;
  3929. FUNCTION IconIDToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;
  3930.                      iconID: INTEGER): OSErr;
  3931.          INLINE  $303C, $0913, $ABC9;
  3932. FUNCTION IconSuiteToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;
  3933.                         theIconSuite: Handle): OSErr;
  3934.          INLINE  $303C, $0914, $ABC9;
  3935. FUNCTION IconMethodToRgn(theRgn: RgnHandle; iconRect: Rect; align: IconAlignmentType;
  3936.                          theMethod: IconGetter; yourDataPtr: Ptr): OSErr;
  3937.          INLINE  $303C, $0915, $ABC9;
  3938. FUNCTION SetSuiteLabel(theSuite: Handle; theLabel: INTEGER): OSErr;
  3939.          INLINE  $303C, $0316, $ABC9;
  3940. FUNCTION GetSuiteLabel(theSuite: Handle): INTEGER;
  3941.          INLINE  $303C, $0217, $ABC9;
  3942. FUNCTION GetIconCacheData(theCache: Handle; VAR theData: Ptr): OSErr;
  3943.          INLINE  $303C, $0419, $ABC9;
  3944. FUNCTION SetIconCacheData(theCache: Handle; theData: Ptr): OSErr;
  3945.          INLINE  $303C, $041A, $ABC9;
  3946. FUNCTION GetIconCacheProc(theCache: Handle; VAR theProc: IconGetter): OSErr;
  3947.          INLINE  $303C, $041B, $ABC9;
  3948. FUNCTION SetIconCacheProc(theCache: Handle; theProc: IconGetter): OSErr;
  3949.          INLINE  $303C, $041C, $ABC9;
  3950. FUNCTION PlotIconHandle(theRect: Rect; align: IconAlignmentType;
  3951.                         transform: IconTransformType; theIcon: Handle): OSErr;
  3952.          INLINE  $303C, $061D, $ABC9;
  3953. FUNCTION PlotSICNHandle(theRect: Rect; align: IconAlignmentType;
  3954.                         transform: IconTransformType; theSICN: Handle): OSErr;
  3955.          INLINE  $303C, $061E, $ABC9;
  3956. FUNCTION PlotCIconHandle(theRect: Rect; align: IconAlignmentType;
  3957.                          transform: IconTransformType; theCIcon: CIconHandle): OSErr;
  3958.          INLINE  $303C, $061F, $ABC9;
  3959. /* C Typedefs */
  3960. typedef pascal OSErr   (*IconAction)(ResType theType, Handle *theIcon, void *yourDataPtr);
  3961. typedef pascal Handle  (*IconGetter)(ResType theType, void *yourDataPtr);
  3962. typedef unsigned long  IconSelectorValue;
  3963. typedef short          IconAlignmentType;
  3964. typedef short          IconTransformType;
  3965. /* C Glue */
  3966. pascal OSErr PlotIconID(const Rect *theRect, IconAlignmentType align,
  3967.                         IconTransformType transform, short theResID)
  3968.        =  {0x303C, 0x0500, 0xABC9};
  3969. pascal OSErr NewIconSuite(Handle *theIconSuite)
  3970.        =  {0x303C, 0x0207, 0xABC9};
  3971. pascal OSErr AddIconToSuite(Handle theIconData, Handle theSuite, ResType theType)
  3972.        =  {0x303C, 0x0608, 0xABC9};
  3973. pascal OSErr GetIconFromSuite(Handle *theIconData, Handle theSuite, ResType theType)
  3974.        =  {0x303C, 0x0609, 0xABC9};
  3975. pascal OSErr ForEachIconDo(Handle theSuite, IconSelectorValue selector, IconAction action,
  3976.                            void *yourDataPtr)
  3977.        =  {0x303C, 0x080A, 0xABC9};
  3978. pascal OSErr GetIconSuite(Handle *theIconSuite, short theResID, IconSelectorValue selector)
  3979.        =  {0x303C, 0x0501, 0xABC9};
  3980. pascal OSErr DisposeIconSuite(Handle theIconSuite, Boolean disposeData)
  3981.        =  {0x303C, 0x0302, 0xABC9};
  3982. pascal OSErr PlotIconSuite(const Rect *theRect, IconAlignmentType align,
  3983.                            IconTransformType transform, Handle theIconSuite)
  3984.        =  {0x303C, 0x0603, 0xABC9};
  3985. pascal OSErr MakeIconCache(Handle *theHandle, IconGetter makeIcon, void *yourDataPtr)
  3986.        =  {0x303C, 0x0604, 0xABC9};
  3987. pascal OSErr LoadIconCache(const Rect *theRect, IconAlignmentType align,
  3988.                            IconTransformType transform, Handle theIconCache)
  3989.        =  {0x303C, 0x0606, 0xABC9};
  3990. pascal OSErr PlotIconMethod(const Rect *theRect, IconAlignmentType align,
  3991.                             IconTransformType transform, IconGetter theMethod,
  3992.                             void *yourDataPtr)
  3993.        =  {0x303C, 0x0805, 0xABC9};
  3994. pascal OSErr GetLabel(short labelNumber, RGBColor *labelColor, Str255 labelString)
  3995.        =  {0x303c, 0x050B, 0xABC9};
  3996. pascal Boolean PtInIconID(Point testPt, Rect *iconRect, IconAlignmentType alignment,
  3997.                           short iconID)
  3998.        =  {0x303c, 0x060D, 0xABC9};
  3999. pascal Boolean PtInIconSuite(Point testPt, Rect *iconRect, IconAlignmentType alignment,
  4000.                              Handle theIconSuite)
  4001.        =  {0x303c, 0x070E, 0xABC9};
  4002. pascal Boolean PtInIconMethod(Point testPt, Rect *iconRect, IconAlignmentType alignment,
  4003.                               IconGetter theMethod, void *yourDataPtr)
  4004.        =  {0x303c, 0x090F, 0xABC9};
  4005. pascal Boolean RectInIconID(Rect *testRect, Rect *iconRect, IconAlignmentType alignment,
  4006.                             short iconID)
  4007.        =  {0x303c, 0x0610, 0xABC9};
  4008. pascal Boolean RectInIconSuite(Rect *testRect, Rect *iconRect, IconAlignmentType alignment,
  4009.                                Handle theIconSuite)
  4010.        =  {0x303c, 0x0711, 0xABC9};
  4011. pascal Boolean RectInIconMethod(Rect *testRect, Rect *iconRect, IconAlignmentType alignment,
  4012.                                 IconGetter theMethod, void *yourDataPtr)
  4013.        =  {0x303c, 0x0912, 0xABC9};
  4014. pascal OSErr IconIDToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType alignment,
  4015.                          short iconID)
  4016.        =  {0x303c, 0x0613, 0xABC9};
  4017. pascal OSErr IconSuiteToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType alignment,
  4018.                             Handle theIconSuite)
  4019.        =  {0x303c, 0x0714, 0xABC9};
  4020. pascal OSErr IconMethodToRgn(RgnHandle theRgn, Rect *iconRect, IconAlignmentType alignment,
  4021.                              IconGetter theMethod, void *yourDataPtr)
  4022.        =  {0x303c, 0x0915, 0xABC9};
  4023. pascal OSErr SetSuiteLabel(Handle theSuite, short theLabel)
  4024.        =  {0x303C, 0x0316, 0xABC9};
  4025. pascal short GetSuiteLabel(Handle theSuite)
  4026.        =  {0x303C, 0x0217, 0xABC9};
  4027. pascal OSErr GetIconCacheData(Handle theCache, void **theData)
  4028.        =  {0x303C, 0x0419, 0xABC9};
  4029. pascal OSErr SetIconCacheData(Handle theCache, void *theData)
  4030.        =  {0x303C, 0x041A, 0xABC9};
  4031. pascal OSErr GetIconCacheProc(Handle theCache, IconGetter *theProc)
  4032.        =  {0x303C, 0x041B, 0xABC9};
  4033. pascal OSErr SetIconCacheProc(Handle theCache, IconGetter theProc)
  4034.        =  {0x303C, 0x041C, 0xABC9};
  4035. pascal OSErr PlotIconHandle(const Rect *theRect, IconAlignmentType align,
  4036.                             IconTransformType transform, Handle theIcon)
  4037.        =  {0x303C, 0x061D, 0xABC9};
  4038. pascal OSErr PlotSICNHandle(const Rect *theRect, IconAlignmentType align,
  4039.                             IconTransformType transform, Handle theSICN)
  4040.        =  {0x303C, 0x061E, 0xABC9};
  4041. pascal OSErr PlotCIconHandle(const Rect *theRect, IconAlignmentType align,
  4042.                              IconTransformType transform, CIconHandle theCIcon)
  4043.        =  {0x303C, 0x061F, 0xABC9};
  4044. Further Reference:
  4045. •    Inside Macintosh, Volume V, QuickDraw chapter
  4046. •    Inside Macintosh, Volume VI, Finder Interface chapter
  4047. QD 19 - Fixed CLUT Devices and the Single Techno Nerd
  4048. QuickDraw    
  4049. Written by:    Guillermo A. Ortiz    December 1992
  4050. Applications that need a given set of colors to look good or make use of color table animation can obtain undesired results in PowerBook 160, PowerBook 180, and PowerBook Duo Macintosh models. The reason for this is that these models sport Fixed Color Devices associated with the flat screen display. This Tech Note describes what a Fixed CLUT device is and presents some solutions to the challenges presented by this display type.
  4051. Topics
  4052. • Fixed CLUT video devices
  4053. • Color table animation and Fixed CLUT devices
  4054. • Different GDevice types and their implications
  4055. Introduction
  4056. Since the introduction of the Macintosh II, Inside Macintosh Volume V defined three types of graphics devices:
  4057.     Indexed CLUT devices     ( gdType = 0 )
  4058.     Fixed CLUT devices     ( gdType = 1 )
  4059.     Direct RGB devices        ( gdType = 2 )
  4060. In the case of indexed devices, values that range from 0 to 2n – 1 (where n is the depth of the device under consideration) point to entries in a table of RGB triplets, thus determining the color associated with a given pixel value. In the case of direct RGB devices, the pixel value is in itself an RGB triplet, therefore defining the color associated with the pixel.
  4061. Up to recently, the only type of indexed CLUT devices known to humanity has been gdType = 0 or Indexed CLUT devices; these are the devices that drive most display boards when set to depths between 1 and 8 (2 colors to 256 colors). As far as color is concerned, the main feature of indexed devices is that the color table for a given device can be changed either directly by using SetEntries or indirectly when the Palette Manager establishes the color environment in response to a palette associated with the frontmost window (if it has one.)
  4062. Fixed CLUT devices enter with the introduction of the PowerBook Duo, PowerBook 160, and PowerBook 180 portables. All these machines support 16-color gray displays (depth = 4); the trick is that although the video does have a color table, it can not be changed at all. What this means is that no color table animation is possible and that the palette manager can not give you the colors you want or affect palette animation.
  4063. Checking for the type of device is really simple. Once you have the device handle all you have to write is something like:
  4064.     DisplayInfo.gdType = (*currDev) -> gdType;
  4065. Naturally, once the application knows it has to deal with a Fixed CLUT device, it may want to do something based on this information.
  4066. So What!
  4067. At this point the smart reader is probably starting to wonder what kind of help this Tech Note is going to provide as far as not having to stay alone at home this Friday evening: Sadly enough the answer is none. Nevertheless it can help avoid support calls from PowerBook users when their favorite application starts acting weird.
  4068. Now, the first thing to emphasize is that most developers don’t have to worry about this—it is not as if your word processing application is going to start crashing. However, applications that by their nature have to modify the color environment to run properly have to take some precautions.
  4069. We will discuss some scenarios and the implications for each one. Other possibilities may exist, but these will help you understand the issues.
  4070. • Non-Color-Intensive Applications Need Not to Worry
  4071. Applications that deal with text and black-and-white stuff should not be concerned. Even applications that provide limited color capabilities will have no problem.
  4072. • Color-Enhanced Applications
  4073. Certain applications such as games and presentation packages require a given set of colors to look “cool.” Probably the Palette Manager is used in order to assure that the minimal set of colors is present. Applications like these need to make sure there is a fallback similar to the one used when the application is running in a black-and-white environment. Note that prompting the user to change the depth won’t do much good.
  4074. • Color-Intensive Applications
  4075. Applications that require heavy manipulation of the color environment to do their stuff need to be ready to take the path taken when the machine the user is on has no color or can not be set to the optimum depth. Applications that call the video driver directly such as those that animate colors by calling the _Control routine especially need to make sure the device in question is capable of color table changing; the control call returns an error -17 (controlErr - Driver can not respond to Control call) if SetEntries or DirectSetEntries is tried.
  4076. Note 1:    The PowerBook Duo can be docked to a number of different docking stations, the currently available docking stations are:
  4077.     a. Duo Dock. In this case the flat display is not used at all and the main device becomes an Indexed CLUT device with depths depending on the monitor being used.
  4078.     b. Mini Dock. The main display is still in use and the monitor configuration for the machine becomes a two-display system with one Indexed CLUT device (external display) and a Fixed CLUT device (flat display).
  4079. Note 2:    PowerBook Duo, PowerBook 160, and PowerBook 180 Macintosh computers can be configured in a display mode called Mirroring using the PowerBook Display control panel. In this configuration the system sees two devices that share the same bounds. The result is that drawing to the main device results in drawing into both screens with QuickDraw taking care of the details such as different depths and color/black-and-white settings.
  4080. In Conclusion
  4081. Fixed CLUT devices add a little twist to the things that an application developer has to be aware of. With the popularity of the PowerBook line, it becomes really important that applications know how to configure in this case in order to continue providing smooth performance under the varied conditions now existent in the Macintosh family of computers.
  4082. Further Reference:
  4083. •    Inside Macintosh, Volume VI, The Graphics Devices Manager
  4084. •    Macintosh Duo System Developer Note (Available on the Developer CD)
  4085. •    Macintosh PowerBook 160 and Macintosh PowerBook 180 Developer Note (Available on the Developer CD)
  4086. QD 20 - _PackBits : Things You Wanted to Know About* *But Were Afraid to Ask
  4087. QuickDraw    
  4088. Revised by:    Guillermo Ortiz, Jon Zap, and Forrest Tanaka    January 1992
  4089. Written by:    Cameron Birse    November 1987
  4090. This Technical Note describes the format of data packed by the Toolbox utility _PackBits and documents a change to the srcBytes limit and possible worst case. Although you can simply unpack this data using _UnPackBits, Apple provides this information for the terminally curious and for those manipulating MacPaint® documents or PICT files by hand. 
  4091. Warning: This format information is subject to change.
  4092. Changes since November 1990: A warning has been added about the handling of a flag-counter byte value of -128.
  4093. Length Doesn’t Matter
  4094. Inside Macintosh, Volume I-470, describes the Pascal interface to the _PackBits trap as follows:
  4095.     PROCEDURE PackBits(VAR srcPtr,dstPtr:Ptr; srcBytes:INTEGER);
  4096. The accompanying text states that srcBytes, the length of your uncompressed data, should not be greater than 127, and that in the worst case, the compressed data can be srcBytes + 1. To pack more than 127 bytes, you had to break the data up into 127-byte groups and call _PackBits on each group. Beginning with system software version 6.0.2, this limit of 127 bytes is no longer valid. The new limit is 32,767 bytes, which is the maximum positive number that srcBytes can hold. The worst case can be determined according to the following formula:
  4097.     (srcBytes + (srcBytes+126) DIV 127)
  4098. which is comparable to what you would get if you broke up the data into 127-byte groups and picked up an additional byte for each group.
  4099. Mommy, How Do They Make Packed Bits?
  4100. The first byte is a flag-counter byte that specifies whether or not the the following data is packed, and the number of bytes involved. If this first byte is a negative number, then the following data is packed. In this case, the number is the two’s complement of a zero-based count of the number of times the data byte repeats when expanded. There is one data byte following this first byte in packed data. The byte after the data byte is the next flag-counter byte.
  4101. If the flag-counter byte is a positive number, then the following data is unpacked. In this case, the number is a zero-based count of the number of incompressible data bytes that follow. There are (flag-counter+1) data bytes following the flag-counter byte. The byte after the last data byte is the next flag-counter byte.
  4102. Note that there is no way to know, given a pointer to the start of packed data, when you have reached the end of the packed data. This is why you need to know either the length of the packed or unpacked data before you start unpacking. _UnPackBits requires the length of the unpacked data.
  4103. Warning:    _PackBits never generates the value -128 ($80) as a flag-counter byte, but a few PackBits-like routines that are built into some applications do. _UnpackBits handles this situation by skipping any flag-counter byte with this value and interpreting the next byte as the next flag-counter byte. If you’re writing your own UnpackBits-like routine, make sure it handles this situation in the same way.
  4104. Consider the following example:
  4105. Unpacked data:
  4106.     AA AA AA 80 00 2A AA AA AA AA 80 00 2A 22 AA AA AA AA AA AA AA AA AA AA
  4107. After being packed by _PackBits:
  4108.     FE AA                    ; (-(-2)+1) = 3 bytes of the pattern $AA
  4109.     02 80 00 2A              ; (2)+1 = 3 bytes of discrete data
  4110.     FD AA                    ; (-(-3)+1) = 4 bytes of the pattern $AA
  4111.     03 80 00 2A 22           ; (3)+1 = 4 bytes of discrete data
  4112.     F7 AA                    ; (-(-9)+1) = 10 bytes of the pattern $AA
  4113.        or
  4114.     FE AA 02 80 00 2A FD AA 03 80 00 2A 22 F7 AA
  4115.     *     *           *     *              *
  4116. The bytes with the asterisk (*) under them are the flag-counter bytes. _PackBits packs the data only when there are three or more consecutive bytes with the same data; otherwise it just copies the data byte for byte (and adds the count byte).
  4117. Note:    The data associated with some PICT opcodes, $0098 (PackBitsRect) and $0099 (PackBitsRgn), contain PixData which is basically made of _PackBits data. It should be noted, though, that the format for PixData includes a byteCount or length in addition to the data described in this Note.
  4118. For example, the following is the result of decoding a sample PICT2:
  4119. data 'PICT' (25534) {
  4120.     0936 0000 0000 0007 001E                /* pic size, picFrame */
  4121.     0011 02FF                               /* pict2              */
  4122.     0C00                                    /* header             */
  4123.          FFFF FFFF 0000 0000 0000 0000 001E 0000 0007 0000 0000 0000
  4124.     001E                                    /* def hilite         */
  4125.     0001                                    /* clipRgn            */
  4126.          000A 0000 0000 0007 001E
  4127.     0098                                    /* PackBitsRect       */
  4128.          801E                               /* rowbytes of 30     */
  4129.          0000 0000 0007 001E                /* Bounds             */
  4130.          0000                               /* packType           */
  4131.          0000                               /* version            */
  4132.          0000 0000                          /* packSize           */
  4133.          0048 0000                          /* hRes               */
  4134.          0048 0000                          /* vRes               */
  4135.          0000                               /* pixelType          */
  4136.          0008                               /* pixelSize          */
  4137.          0001                               /* cmpCount           */
  4138.          0008                               /* cmpSize            */
  4139.          0000 0000                          /* planeBytes         */
  4140.          0000 1F10                          /* pmTable            */
  4141.          0000 0000                          /* pmReserved         */
  4142.         /*color table*/
  4143.               0000 4CBC                     /* ctSeed             */
  4144.               8000                          /* ctFlags            */
  4145.               00FF                          /* ctSize             */
  4146.                    0000 FFFF FFFF FFFF
  4147.                    ...                 /* 254 ColorSpec's omitted */
  4148.                    0000 0000 0000 0000
  4149.          0000 0000 0007 001E                /* srcRect            */
  4150.          0000 0000 0007 001E                /* dstRect            */
  4151.          0000                               /* srcCopy            */
  4152.          /* Now we have the scan line data packed as follows:
  4153.             [bytecount for current scan line] [data as defined above]
  4154.             If rowBytes is > 250 then byteCount is a word else is a byte
  4155.             (in this case, byteCount is a byte)
  4156.             note that each unpacked row adds to 30 rowBytes
  4157.          */
  4158.          /* line 1, byte count is 2 (best case for a row)   */
  4159.          02
  4160.             E3 FF                /* -(-29) + 1 = 30 FF's    */
  4161.          /* line 2, byte count is 19 (0x13)                 */
  4162.          13
  4163.             01 FF 23             /* 1+1 data bytes          */
  4164.             FE 00                /* -(-2)+1 0's             */
  4165.             FC 23                /* -(-4)+1 0x23's          */
  4166.             FE 00                /* 3 0's                   */
  4167.             FC 23                /* 5 0x23's                */
  4168.             FE 00                /* 3 0's                   */
  4169.             FC 23                /* 5 0x23's                */
  4170.             FE 00                /* 3 0's                   */
  4171.             00 FF                /* 1 data byte             */
  4172.          /* line 3, byte count is 28                        */
  4173.          1C
  4174.             02 FF 00 23          /* 3 data bytes            */
  4175.             FE 00                /* 3 0's                   */
  4176.             FE 23                /* 3 0x23's                */
  4177.             01 00 23             /* 2 data bytes            */
  4178.             FE 00                /* 3 0's                   */
  4179.             FE 23                /* 3 0x23's                */
  4180.             01 00 23             /* 2 data bytes            */
  4181.             FE 00                /* 3 0's                   */
  4182.             FE 23                /* 3 0x23's                */
  4183.             04 00 23 00 00 FF    /* 5 data bytes            */
  4184.          /* line 4, byte count is 31 (worst case for a row) */
  4185.          1F
  4186.             03 FF 00 00 23       /* 4 data bytes            */
  4187.             FE 00                /* 3 0's                   */
  4188.             00 23                /* 1 data byte             */
  4189.             FE 00                /* 3 0's                   */
  4190.             00 23                /* 1 data byte             */
  4191.             FE 00                /* 3 0's                   */
  4192.             00 23                /* 1 data byte             */
  4193.             FE 00                /* 3 0's                   */
  4194.             00 23                /* 1 data byte             */
  4195.             FE 00                /* 3 0's                   */
  4196.             00 23                /* 1 data byte             */
  4197.             FE 00                /* 3 0's                   */
  4198.             02 23 00 FF          /* 3 data bytes            */
  4199.          /* line 5, byte count is 28                        */
  4200.          1C
  4201.             01 FF 00             /* 2 data bytes            */
  4202.             FE 23                /* 3 0x23's                */
  4203.             01 00 23             /* 2 data bytes            */
  4204.             FE 00                /* 3 0's                   */
  4205.             FE 23                /* 3 0x23's                */
  4206.             01 00 23             /* 2 data bytes            */
  4207.             FE 00                /* 3 0's                   */
  4208.             FE 23                /* 3 0x23's                */
  4209.             01 00 23             /* 2 data bytes            */
  4210.             FE 00                /* 3 0's                   */
  4211.             FE 23                /* 3 0x23's                */
  4212.             00 FF                /* 1 data byte             */
  4213.          /* line 6, byte count is 18                        */
  4214.          12
  4215.             00 FF                /* 1 data byte             */
  4216.             FC 23                /* 5 0x23's                */
  4217.             FE 00                /* 3 0's                   */
  4218.             FC 23                /* 5 0x23's                */
  4219.             FE 00                /* 3 0's                   */
  4220.             FC 23                /* 5 0x23's                */
  4221.             FE 00                /* 3 0's                   */
  4222.             FD 23                /* 4 0x23's                */
  4223.             00 FF                /* 1 data byte             */
  4224.          /* line 7, byte count is 2 (best case for a row)   */
  4225.          02
  4226.             E3 FF                /* 30 0xFF's               */
  4227.          00  /* pad so next command starts at word boundary */
  4228.     00FF                         /*end of pic               */
  4229. };
  4230. Further Reference:
  4231. •    Inside Macintosh, Volume I-465, The Toolbox Utilities
  4232. •    Inside Macintosh, Volume V-39, Color QuickDraw
  4233. •    Technical Note M.PT.MacPaintDoc —
  4234.          MacPaint Document Format
  4235. MacPaint is a registered trademark of Claris Corporation.
  4236. QD 21 - Of Time and Space and _CopyBits
  4237. QuickDraw    
  4238. Written by:    Forrest Tanaka    June 1990
  4239. This Technical Note describes the various factors that can influence the speed of _CopyBits so that developers can set up conditions to achieve the best performance for the particular situation.
  4240. Can You Influence the Speed of _CopyBits?
  4241. _CopyBits has never been an “easy” QuickDraw routine, like _LineTo or even _OpenPort.  Most programmers who are just beginning to adjust themselves to the Macintosh usually have to give _CopyBits a few tries before the right bits copy to the right places.  Even many who feel that they have become Macintosh programmers still see reflections in their monitors of furrows between their eyebrows as they begin to press the key labelled “C.”
  4242. _CopyBits is one of those routines that is so full of subtlety, it has the beginnings of something that could be considered to be personality.  One subtlety involves the second most important thought that’s on the minds of any computer programmer:  execution speed.  Why is _CopyBits fast?  Why is it slow?  Can I influence its speed?  Is there really a clandestine state of reason?  Is there a price to speed?
  4243. Influences on the Speed of _CopyBits
  4244. Yes, you can influence the speed of _CopyBits.  Yes, it’s even predictable.  And yes, it’s possible that you have to compromise to get the maximum speed.  This Note is intended to give you a deeper understanding of the ways that the speed of _CopyBits can be affected; and hopefully you can then set up conditions for a _CopyBits call without the disturbing notion that someone else might be doing the same thing just a little bit better than you.
  4245. This Note talks about every factor that affects the speed of _CopyBits that I can think of and that can be reasonably controlled by a programmer or the person using an application.  There are other factors not mentioned in this Note because I felt that they were just too esoteric to describe with any meaning.
  4246. In each case, this Note tries to give real-life examples showing the effect of each factor.  These examples are just to give you a relative idea of the importance of each effect.  In real life, the effects of the different factors give results that could be a lot different from the results presented in this Note.  Each example is based on 100 _CopyBits calls from an off-screen pixel map to the screen on a Macintosh IIcx with an Apple Extended Video Card which is running System Software 6.0.5 and 32-Bit QuickDraw 1.2.  The off-screen pixel map is eight bits deep with the standard eight-bit color table and 256 pixels high by 256 pixels wide.  The screen is also in eight-bit color mode.  Calling _CopyBits to copy the entire off-screen pixel map to the screen 100 times takes 204 ticks, and this Note refers to this figure as the “standard test.”  Since a tick on a Macintosh is approximately 1/60 of a second, the standard test runs at slightly less than 30 frames per second.  As this Note discusses each factor, it presents an example with that factor changing and all other factors remaining the same as the standard test, which allows you to compare performance of the changed factor to that of the standard test of 204 ticks.
  4247. What follows is a discussion of each factor that can influence the speed of _CopyBits, in no particular order.
  4248. Dimensions of the Copied Area
  4249. One of  the most obvious factors has to do with the dimensions of the copied area.  _CopyBits takes as parameters two rectangles which specify the portion of the source pixel map from which you want to copy and the portion of the destination pixel map to which you want to copy it.  All other factors being equal, the larger the rectangles, the more pixels _CopyBits has to copy and the longer it takes to do the job.  To keep _CopyBits as fast as possible, copy the smallest rectangle possible.
  4250. Modifying the standard test so that _CopyBits only copies a 128-pixel wide by 128-pixel tall area produces a result of 109 ticks, which compares to the 204 tick performance for a 256-pixel wide by 256-pixel tall area.
  4251. QuickDraw is usually faster drawing wide things than it is drawing tall things, because consecutive pixels in memory are displayed horizontally.  Drawing a series of pixels that are next to each other horizontally is easy because QuickDraw simply has to set consecutive memory locations, while drawing a series of pixels that are next to each other vertically is just a little bit harder because the address of each pixel must be calculated.  _CopyBits is no exception to this general rule; it copies a row of pixels, goes to the next row, copies that row, goes to the next row, and so on.  The time spent going between rows is a lot more than the time going between pixels on one row, so the effect is that _CopyBits is faster copying a short and wide section of a pixel map than it is copying a tall and narrow one.  To keep _CopyBits as fast as possible, copy the shortest rectangle possible.
  4252. Modifying the standard test again so that the source and destination rectangles are 256 pixels wide by 50 pixels tall produces a result of 110 ticks, while modifying it so that the source and destination rectangles are 50 pixels wide by 256 pixels tall results in a time of 123 ticks.  These 13 ticks may not seem like a big deal, but combined with other factors, there may be a case where they make a big difference.
  4253. Shape and Size of the Clip, Visible, and Mask Regions
  4254. _CopyBits always makes sure that it stays within the lines, so to speak.  _CopyBits copies pixels clipped to the maskRgn that you pass as the last parameter to the call.  If the destination is the current GrafPort, _CopyBits additionally clips to a region that’s the intersection of the clipRgn and visRgn of the port.  If the intersection of these three regions is not rectangular, then _CopyBits has to check each pixel to make sure it falls within the intersection, and this check slows _CopyBits down.  If the intersection of these three regions is rectangular, then _CopyBits takes the fast case of copying constant-sized rows.  To keep _CopyBits as fast as possible, make sure the intersection of the clipRgn and visRgn of the destination GrafPort and the maskRgn is rectangular.  Of course, if the destination GrafPort is a window, then the visRgn is under the user’s control.
  4255. In general, if the region that you are copying into has straight vertical edges for the most part, the time penalty of using a non-rectangular region is not that bad.  Regions that only have small portions that are straight and vertical are the ones that slow _CopyBits down in a big way.  Regions that are twisted or that have holes or islands can also have a big effect upon the speed, depending upon how complicated they are.  As a rule of thumb, if a region looks like it slows _CopyBits, it probably does.
  4256. Modifying the standard test so the maskRgn is set to a circle that inscribes the example pixel map results in a time of 303 ticks, which is considerably longer than the standard test result of 204 ticks that involved copying a much larger area.  Modifying the maskRgn to a square with 226 pixels per side, which has about the same total area of the circle just used, results in a time of 176 ticks.
  4257. Transfer Modes
  4258. Macintoshes without Color QuickDraw have eight transfer modes that work with _CopyBits, while those Macintoshes with Color QuickDraw get an additional nine modes.  Because the algorithms for each of these modes can be pretty different from the others, the time it takes _CopyBits to work with each of these modes can vary radically.  For several of these modes, the speed of _CopyBits can vary a lot depending upon the particular image being copied and the image over which this image is copied.  It can also vary non-linearly depending upon the depth of the pixel maps.  The arithmetic modes in particular are highly optimized for 32-bit deep pixel maps.
  4259. The standard test copies a fairly average-looking ray-traced image to a white background.  Modifying the standard test to erase the background between each of the 100 calls to _CopyBits produced the following results for the modes listed (the tests were obviously also changed to reflect the proper mode.  In addition, to make the results a little more meaningful, the time it took to erase the background has been subtracted from each result.
  4260. srcCopy    204    notSrcCopy    469    addOver    1500    adMax    1504
  4261. srcOr        436    notSrcOr    444    addPin    1514    adMin    1501
  4262. srcBic    441    notSrcBic    441    subOver    1493    blend    1553
  4263. srcXor    438    notSrcXor    436    subPin    1525    transparent    1107
  4264.                         hilite    3127
  4265. Of course, the amount of time taken by some of these modes can be changed by changing the image to copy and the image over which it is copied.  These figures are just to give an idea of how fast or slow some of these modes are in this particular situation.
  4266. There is actually one more mode which is not mentioned:  ditherCopy.  Apple introduced this mode with 32-Bit QuickDraw, and it makes _CopyBits do error-diffusion dithering when copying a pixel map from one depth to a pixel map of a lesser depth or to a pixel map of the same depth with a different color table.  The speed of this transfer mode can be very fast or very slow, depending upon what pixel depths and colors are used and the particular image being copied.  The ditherCopy mode is not included in the table since the range of figures is potentially very large; play with it and see for yourself.  For more information about this mode, refer to the Color QuickDraw chapter in Inside Macintosh, Volume VI and the 32-Bit QuickDraw Developers’ Notes from APDA.
  4267. Colorization
  4268. There is a variation of _CopyBits if the destination pixel map is the current port and the foreground color is not black or the background color is not white.  If this is the case, then the source image is colorized when it’s copied.  For details, see Technical Note #163, Adding Color with _CopyBits.  Because this colorization requires extra processing, _CopyBits slows down.  To keep _CopyBits as fast as possible, make sure the foreground color is black, the background color is white, and that the current GDevice pixel map’s color table has white in the first position and black in the last position.
  4269. Modifying the standard test so that the foreground color is pure red and the background color pure blue produces a result of 579 ticks.
  4270. Pixel Alignment
  4271. The alignment of pixels in the source pixel map relative to their alignment the destination pixel map can be surprisingly important to the speed of _CopyBits, but what is pixel alignment?  Following is an example to demonstrate the concept of pixel alignment.  Imagine you want to perform a _CopyBits on a one-bit-per-pixel off-screen pixel map into a window on a one-bit-per-pixel screen, and the window is three pixels from the left edge of the screen.
  4272. If you copy the entire off-screen pixel map to the left edge of the window, then _CopyBits must realign the pixels.  Since the leftmost pixels of the off-screen pixel map are on a byte boundary, but the left edge of the window is three pixels away from a byte boundary, _CopyBits has to shift (or realign) each byte from the off-screen pixel map by three pixels before placing it on the screen.  The process of aligning the pixels slows down _CopyBits.
  4273. Figure 1 shows an example of this realignment.  An off-screen bit map specified by a pointer to a BitMap called offScreen is being copied to a window specified by a WindowPtr called window.  window, which is 256 pixels wide and 256 pixels high, is positioned 50 pixels from the top of the screen and three pixels from the left edge of the screen.  The screen has 512 pixels horizontally and 342 pixels vertically.  The source rectangle that is passed to _CopyBits is sourceRect and the destination rectangle is destinationRect.  Because offScreen is misaligned by three pixels, _CopyBits has to shift offScreen by three pixels before placing the image on the screen.
  4274. Figure 1–offscreen Needs Realignment
  4275. By adjusting the off-screen pixel map so that its leftmost pixels are also three pixels away from a byte boundary, _CopyBits can just copy the bytes without shifting, which is a lot faster.  This example holds true on all Macintosh models, whether they have Color QuickDraw or not.  To keep _CopyBits as fast as possible, make sure the pixels in memory are aligned with the pixels on the screen.  Figure 2 shows the same situation as Figure 1, except that offScreen is now properly aligned to window.
  4276. Figure 2–offscreen Aligned
  4277. Many, if not most, Color QuickDraw Macintoshes have video cards that can display one pixel per byte, so one would think that pixel alignment does not apply in these cases, since all pixels are at byte boundaries.  This statement is true enough, but there is still another kind of alignment that should be done on these machines.  Macintoshes with Color QuickDraw generally have full 32-bit microprocessors, and these microprocessors are at their fastest when they can transfer long words aligned on long-word boundaries in memory.
  4278. Modifying the last example so that the off-screen pixel map and the screen are both eight-bits-per-pixel, the pixel at the extreme top left corner of the off-screen pixel map is located at a long-word boundary, because the Macintosh Memory Manager forces it to be located there; however, the pixel at the extreme top left corner of the window is located three bytes away from the previous long-word boundary.  No bit shifting is needed, because each pixel takes up a whole byte, but _CopyBits does have to take the non-optimum case of copying long words on non-long-word boundaries.  This case works fine, but it is not quite as fast as it could be.  To keep _CopyBits as fast as possible, make sure pixels in the source and destination pixel maps are aligned on long-word boundaries.
  4279. Since 1984, Macintosh programmers have been told that rowBytes must be even.  That is still true, but to allow _CopyBits to copy an entire pixel map on long-word boundaries, rowBytes must be a multiple of four so that every line in a pixel map begins on a long-word boundary.  The following formula can be used to find the minimum rowBytes needed for a pixel map’s bounds rectangle with right and left coordinates of bounds.right and bounds.left, and a pixel depth of pixelDepth:
  4280. rowBytes := ((pixelDepth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  4281. Off-screen GWorld support, which was introduced with 32-Bit QuickDraw, can automatically set up a pixel map so that it’s properly aligned to any part of the destination pixel map or bit map.  You can specify that you want this by passing zero for the pixel depth and passing the rectangle of the destination area in global coordinates.  See the 32-Bit QuickDraw Developers’ Notes and “Braving Offscreen Worlds” in d e v e l o p, January 1990 for details.
  4282. The way that _NewGWorld aligns a GWorld is to set up the off-screen pixel map so that its rowBytes is four bytes wider than one would normally calculate.  Four bytes is the maximum amount that any pixel map would have to be realigned at any pixel depth.  The bounds rectangle’s left coordinate is set to the negative of the left coordinate of the destination rectangle in global coordinates modulo (32 / pixel depth), because this is maximum amount that a pixel map must be shifted to achieve perfect alignment.  To build on the earlier example, assume you have a 128-pixel wide, eight-bit deep, off-screen pixel map to copy to a window that is three pixels away from the left edge of an eight-bit color screen.
  4283. First, the rowBytes for the off-screen pixel map is set to 131 to allow room for realignment.  To align the off-screen pixel map to the on-screen window, the left coordinate of the off-screen bit map’s bounds is set to -3 and the right coordinate is still at 128.  Notice that the off-screen pixel map’s bounds is now 131 pixels wide.  Now, the pixels in the off-screen pixel map with a horizontal coordinate of 0 are located three bytes away from the previous long-word boundary.  The pixels on the left edge of the window are also located three bytes away from the previous long-word boundary, so _CopyBits can copy long words on long-word boundaries.
  4284. If a user moves the window so that it’s two pixels from the left edge of the screen, the off-screen pixel map must be realigned.  _UpdateGWorld is used to do this.  It changes the left coordinate of the off-screen pixel map’s bounds rectangle to -2 and then it shifts all the pixels in the off-screen pixel map one pixel to the left.  The extra four bytes in each row provide the room for this shifting.  (Gives you some new respect for the off-screen support, doesn’t it?)
  4285. This same discussion applies to any pixel depth, though shallower pixel depths require bit shifting rather than byte shifting.  The same principles apply, though.  Notice that in a 32-bit deep pixel map, all pixels are aligned on long-word boundaries, so no bit shifting or byte shifting ever needs to be done on one of those.  _NewGWorld still adds four to rowBytes even in this case, however.
  4286. Modifying the standard test so that the source and destination pixel maps are four bits deep with perfect pixel alignment produces a result of 78 ticks; however, if the destination pixel map is one pixel left of perfect alignment, the result is 228 ticks.
  4287. Speed of the Hardware, Of Course
  4288. Obviously, the speed of the machine your application is running on affects the speed of _CopyBits.  To make _CopyBits as fast as possible, spend a lot of money.  However, there is more to the speed of _CopyBits than the speed of the Macintosh itself.  When the Macintosh 128K was released, there was only one place for pixel images: main memory.  Today, the situation is more complicated.  If you have a modular Macintosh, the pixel image for the screen is in the memory of a NuBus™ video card.  If you have a Macintosh IIci, you can optionally abandon the NuBus video card and use on-board video which takes up part of main memory.  If you have an 8•24 GC card with enough memory, the pixel images can be cached in the card’s memory along with the screen’s pixel image.
  4289. All of these different locations have different access speeds, and that can affect the speed of _CopyBits.  Additionally, different Macintoshes have different RAM access speeds.  The Macintosh II, IIx, IIcx, and SE/30 have faster RAM than the Macintosh Plus or SE.  The Macintosh IIci RAM access speed is faster still, and the Macintosh IIfx has faster RAM access than the IIci.  Different video cards have different access speeds.  The IIci has a cache card option which can vastly speed up on-board video RAM access speed.  Third-party video cards that work in the Processor Direct Slot of the Macintosh SE and SE/30 have their own speed characteristics as well.
  4290. There can also be a speed cost for crossing the different areas.  If _CopyBits copies between main memory and a NuBus video card, the image data has to be transferred across NuBus.  NuBus is a speed bottleneck, so copying an image across NuBus is slower than copying the image from one part of the screen to another or copying from one part of main memory to another.  Modifying the standard test to create two windows and two off-screen pixel maps—all eight bits deep with the standard color table then doing every combination of copying between off-screens, between windows, and between off-screens and windows produces the following results:
  4291.                 Off-screen to off-screen:    147
  4292.                 Screen to screen:         188
  4293.                 Off-screen to screen:        204
  4294.                 Screen to off-screen:        201
  4295. Performing the standard test on a Macintosh IIfx running System Software 6.0.5 with an Apple Extended Video Card yields a result of 153 ticks, which is not too shabby considering that the transfer is still going through NuBus.
  4296. Depth of Pixel Maps
  4297. This factor is pretty obvious and is sort of similar to the effect of the dimensions of the copied area:  the more bits per pixel there are in the pixel map to copy, the more memory that _CopyBits has to move and the longer it takes to get the job done, assuming that the source and destination pixel maps have the same depth.  To make _CopyBits as fast as possible, make sure the pixel maps are as shallow as possible.
  4298. If _CopyBits has to copy to a pixel map that has a different depth from the source pixel map, the relationship between speed and depth becomes more complicated.  There is a tradeoff between the time taken to change the depth of an image and the absolute amount of data that has to be processed.  Copying from a 1-bit deep pixel map to a 32-bit deep pixel map is not that slow because the amount of image data in the 1-bit deep pixel map is so small.
  4299. Modifying the standard test to transfer a four-bit deep pixel map to another four-bit deep pixel map produces a result of 78 ticks.
  4300. Color Mapping
  4301. Color QuickDraw expects a color table attached to every indexed pixel map.  Color tables specify what color each pixel value in the pixel map represents.  When an application calls _CopyBits to copy a pixel map into another pixel map, _CopyBits reproduces the colors of the image in the source pixel map as closely as possible—even if the colors available in the destination pixel map are different than those available in the source pixel map.  This reproduction is done through a process called “color mapping.”
  4302. When color mapping is done, the source pixel values are transformed into RGBColor records using the source pixel map’s color table.  These RGBColor records are passed to _Color2Index which finds the pixel values of the closest available colors in the current GDevice pixel map’s color table.  This same process is done when the source and destination pixel maps have differing depths.  The color table attached to the destination pixel map is not used in color mapping.  The colors available in the current GDevice pixel map’s color table are used instead.  So, the destination pixel map must have the same colors for the same pixel values as the current GDevice.  Otherwise, the resulting image in the destination pixel map gets the wrong colors.  See Inside Macintosh, Volume V-141, The Color Manager, for a description of _Color2Index.  It’s also helpful to read the “Inverse Tables” section in the same chapter on page V-137.
  4303. Now, if the source color table contains virtually the same colors for the same pixel values as the current GDevice pixel map’s color table, then any particular pixel value has the same color regardless of whether it is in the source or destination pixel map.  In this case, color mapping is a waste of time, because the pixels can be copied directly from the source pixel map to the destination pixel map without a loss of color fidelity.  _CopyBits takes advantage of this special case to yield some big speed improvements.  How is this special case detected?  Before this question is answered, it’s useful to understand how Color QuickDraw uses color tables.
  4304. The ctSeed Field
  4305. The first field in a color table is the ctSeed field.  This LongInt can be thought of as the color table’s version of the scrapCount field of the desk scrap.  Whenever an application calls _ZeroScrap, the desk scrap’s scrapCount is changed.  An application can tell that the desk scrap has changed by checking to see if the scrapCount has changed.  Similarly, whenever the contents of a color table are changed in any way, the ctSeed field should be changed to indicate to anyone using that color table that it has been modified.
  4306. Additionally, Color QuickDraw often uses the ctSeed as a fast check for color table equality.  If two color tables have the same ctSeed, then Color QuickDraw often assumes that their contents are equivalent.
  4307. After creating a new color table, an application has to get a valid value for the ctSeed field, and it can do so with the _GetCTSeed routine.  This routine generates a valid ctSeed value suitable for a new color table.  See Inside Macintosh, Volume V-143, The Color Manager, for a description of _GetCTSeed.
  4308. System Software 7.0 and 32-Bit QuickDraw each offer a routine called _CTabChanged which should be called after a color table is modified.  It takes a handle to the changed color table as a parameter.  If the _CTabChanged routine is not available, then the application should instead change ctSeed to a different valid value by calling _GetCTSeed and assigning the result to ctSeed, just like it’s done when the application creates a new color table.  You must use either one of these methods to tell Color QuickDraw that the color table has changed, or else the modified color table could be confused with the old color table, or with some other color table—this is especially critical if an 8•24 GC card is being used.  See the 32-Bit QuickDraw Developers’ Notes for details about the _CTabChanged routine.
  4309. The ctFlags Field
  4310. The ctFlags field is used as a set of flags that indicate some characteristics of the color table.  Currently, only the top two bits of ctFlags are of any interest to developers.  The most significant bit of ctFlags (bit 15) indicates whether the color table is a sequential color table or an indexed color table.  Bit 14 indicates that the color table is a special kind of sequential table if it is set.  In these kinds of color tables, the value fields indicate a palette entry in the destination window’s palette.  See the Palette Manager section of the 32-Bit QuickDraw Developers’ Notes for a discussion about this capability.
  4311. Sequential Color Tables
  4312. If bit 15 of ctFlags is set, the color table is a sequential color table.  Sequential color tables are usually found attached to GDevice pixel maps and to GWorld pixel maps.
  4313. In sequential color tables, the position of each color in the color table indicates the pixel value to which it corresponds.  For example, the fifth entry in a sequential color table always has a pixel value of four (pixel values start at zero).  The value field of each ColorSpec is not defined in sequential color tables, though they are used in color tables for screen GDevice records to indicate that a particular color is reserved, protected, or both.
  4314. Indexed Color Tables
  4315. If bit 15 and 14 of ctFlags are clear, the color table is an indexed color table.  In indexed color tables, the value field of each ColorSpec indicates the pixel value of the RGB in that ColorSpec.  For example, if the fifth ColorSpec in the color table has a value field containing 10, then that color has a pixel value of 10, not 4, as it would have been if this were a sequential color table.
  4316. Color Mapping or Non-Color Mapping
  4317. As noted before, _CopyBits can detect whether it has to do color mapping or not, so that it can take advantage of the speed benefits of no color mapping if possible.  How is this done?  First, _CopyBits checks to see if the ctSeed field of the source and destination color tables are the same and if the source and destination pixel maps have the same depths.  If both of these conditions are true, then _CopyBits assumes that the two color tables are identical and it just copies the pixels directly without color mapping.  If the ctSeed fields are different, _CopyBits checks manually through all of the colors in the source pixel map’s color table map to see if they map to the same pixel values in the current GDevice pixel map’s color table as they do in their own color table.  If they do, then _CopyBits again takes the fast case.
  4318. So to keep _CopyBits as fast as possible, make sure that the source and destination color tables have virtually the same colors for the same pixel values.  This applies even if one color table is an indexed color table and the other is a sequential color table, or if the source and destination color tables are both indexed but the order of the ColorSpec records differ.
  4319. Modifying the standard test so that the source pixel map has a color table that is the reverse of the standard eight-bit system color table (the grays have low pixel values and the light pinks and yellows have high pixel values) and the destination pixel map has the standard eight-bit system color table produces a result of 470 ticks.
  4320. By the way, color tables do not make any sense for direct pixel maps, so this discussion does not apply to them.  Direct pixel maps do have a color table attached to them, but they’re just there so that an application that assumes that a color table is attached does not bomb.
  4321. Scaling
  4322. If the source and destination rectangles are the same size, _CopyBits has the fairly easy task of just transferring the pixels from the source pixel map to the destination pixel map; however, if the source and destination rectangles are different sizes, _CopyBits has to scale the copied image, which slows it down a lot.  To keep _CopyBits as fast as possible, make sure the source and destination rectangles have the exact same dimensions.
  4323. Modifying the standard test to copy a 128 by 128 pixel portion of the source pixel map to the whole 256 by 256 pixel window produces a result of 1,159 ticks.
  4324. Of Time and Space
  4325. Hopefully, this Note makes it a lot clearer to you how to set up a situation in which your _CopyBits calls are as fast as your situation allows.  It’s important to realize that this Note does not cover every single factor that has an influence on the speed of _CopyBits.  There are many more factors which are just too unpredictable.  For example, _CopyBits is highly optimized for many special cases, and those optimizations can have a big effect on the speed of the copy.  Also, the speed of _CopyBits can be affected by interrupt-level tasks.  It’s up to you to fine tune your programs to your particular situations.
  4326. Further Reference:
  4327. •    Inside Macintosh, Volume I, QuickDraw
  4328. •    Inside Macintosh, Volume V, The Color Manager
  4329. •    Inside Macintosh, Volume VI, Color QuickDraw
  4330. •    Technical Note M.IM.ColorCopyBits, Adding Color With _CopyBits
  4331. •    d e v e l o p, January 1990, “Realistic Color for Real-World Applications”
  4332. •    d e v e l o p, January 1990, “Braving Offscreen GWorlds”
  4333. •    32-Bit QuickDraw Developers’ Notes (APDA)
  4334. NuBus is a trademark of Texas Instruments
  4335. QD 505 - Basic QuickDraw Q&As
  4336. QuickDraw    
  4337. Revised by:    Developer Support Center    September 1993
  4338. Written by:    Developer Support Center    October 1990
  4339. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  4340. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  4341. New Q&As for this month:
  4342. Determining whether CopyBits to a PICT was successful
  4343. Random function requires prior InitGraf call
  4344. GetIconCacheData & SetIconCacheData bug and workaround
  4345. DrawText and DrawString patched to be script aware
  4346. Determining whether CopyBits to a PICT was successful
  4347. Date Written:  1/7/93
  4348. Last reviewed:  3/1/93
  4349. If I’m recording a PICT and doing a CopyBits of a really big image into the PICT, how can I determine whether I’m out of memory?
  4350. ___
  4351. The only reliable way to see whether a CopyBits to a PICT succeeded is after the fact. You need to test the PICT’s picFrame rect (Inside Macintosh Volume V, page V-87) to see whether it’s empty after the CopyBits. The test would look like:
  4352. If (EmptyRect(&(**myPicture).picFrame))
  4353. /* CopyBits failed */
  4354. Random function requires prior InitGraf call
  4355. Date Written:  12/16/92
  4356. Last reviewed:  3/1/93
  4357. The Random function call listed in QuickDraw.h can’t be called from MPW tools without crashing my system. It appears to work when the function is called from applications or cdevs. What could be causing this problem?
  4358. ___
  4359. Use SANE’s RandomX function instead of QuickDraw’s Random function if possible because it gives you better randomness. If you do use QuickDraw’s Random function, be sure to call InitGraf before calling Random from any application or tool. InitGraf initializes a set of QuickDraw global variables for use with the QuickDraw tools; these globals must be initialized because the Random function uses one of them as a seed to generate the random number.
  4360. Normally, it’s not good practice to call initialization routines from within an MPW tool, but calling InitGraf is OK. For more information on which initialization routines are OK to call and which ones aren’t, see page 7 in the MPW Tools chapter of Building and Managing Programs in MPW.
  4361. Sometimes it isn’t obvious when you need to call InitGraf before using the Random function. For example, if you’re using the Macintosh serial tool in a faceless background application, you’ll need to initialize QuickDraw because the tool calls Random.
  4362. GetIconCacheData & SetIconCacheData bug and workaround
  4363. Date Written:  12/8/92
  4364. Last reviewed:  3/1/93
  4365. The Icon Utilities routine GetIconCacheData leaves two bytes of garbage on the stack. This surfaced as a problem for me because it prevented a saved register from getting restored properly. SetIconCacheData probably has the same problem, since it calls the same trap internally. I solved the problem by encapsulating GetIconCacheData within my own static function, like so:
  4366. static OSErr _GetIconCacheData( Handle theCache, void **theData )
  4367. {
  4368. return  GetIconCacheData( theCache, theData );
  4369. }
  4370. #define  GetIconCacheData  _GetIconCacheData
  4371. I then call GetIconCacheData normally. The #define redirects my call to my static wrapper function. The extra two bytes on the stack are recovered when the wrapper function UNLKs and returns. This method has the advantage that the calling code will still work even after the trap is fixed. Am I correct?
  4372. ___
  4373. You’re quite correct; this is a bug in GetIconCacheData and SetIconCacheData. Here’s the offending code from the source:
  4374. EXIT    MOVEA.L    (SP)+, A0   ; Pop return address into A0
  4375.         ADDQ.L     #6, SP      ; Point stack at return value
  4376.         MOVE.W     D0, (SP)    ; Put return value on the stack
  4377.         JMP       (A0)         ; Return
  4378. As you can see, the exit routine is adding 6 to the stack to clear up the input parameters instead of 8 (handle and handle), so an extra word of garbage is being left on the stack. Thanks for letting us know about the problem.
  4379. DrawText and DrawString patched to be script aware
  4380. Date Written:  11/16/92
  4381. Last reviewed:  6/14/93
  4382. While localizing our software, we were told not to assume that a character is only one byte, and thus not to use DrawChar. Does this mean that we can’t use DrawText or DrawString?
  4383. ___
  4384. DrawChar takes a one-byte character as a parameter, so it isn’t suitable for drawing a character whose internal representation requires two bytes. However, DrawText and DrawString (both end up in the same bottleneck procedure StdText) are patched in script-aware systems, and do recognize whether a given byte in a given font-script still corresponds to a one-byte character, or is the first byte of a two-byte character. In the latter case, it transparently fetches the next byte, and looks up the right glyph encoded by a double byte, before actually drawing the glyph.
  4385. QuickDraw globals at INIT time
  4386. Date Written:  6/1/92
  4387. Last reviewed:  9/15/92
  4388. If I call InitGraf before I reference CurrentA5, will CurrentA5 be valid and can the QuickDraw globals be referenced off it? The screenBits bounds values seem screwy on some machines. Does the problem lie with CurrentA5? Should I be referencing A5?
  4389. ___
  4390. Here’s the process used by ShowINIT, which is remarkably compatible with system software and other INITs (and it had better be, because it’s used by more than half the system extensions available):
  4391. 1. It saves the value in the CurrentA5 global to restore it later.
  4392. 2. It points the A5 register at 4 bytes of storage for use by the system.
  4393. 3. It copies the value now in A5 into the CurrentA5 global.
  4394. 4. It calls InitGraf, passing a pointer to the thePort field of a QuickDraw globals structure.
  4395. 5. It opens a port and draws as necessary. [This is where all the functionality goes.]
  4396. 6. After it’s done, it closes its port.
  4397. 7. It copies the value saved in step (1) into the A5 register.
  4398. 8. It copies the restored A5 value into the CurrentA5 global.
  4399. To summarize, ShowINIT saves the A5, creates and initializes its own A5 world, does its drawing, then restores the previous A5 world. For more information on this subject, see the Macintosh Technical Note “Stand-Alone Code.”
  4400. Macintosh QuickDraw LineTo bug and workaround
  4401. Date Written:  4/23/92
  4402. Last reviewed:  7/13/92
  4403. Our zooming function crashes into flames when we pass valid coordinate values to LineTo, as in the following example:
  4404.     SetPort(myPort);
  4405.     MoveTo(154,31619);
  4406.     LineTo(74, -31742); (* You are dead! *)
  4407. What can we do to avoid LineTo crashes like this?
  4408. ___
  4409. The QuickDraw Engineering group is aware of the problem you described. The bug probably is going to be fixed in the next release that includes bug fixes. Given that waiting for a system solution may demand more patience than is reasonable, you may want to consider including in your software some form of workaround that will prevent your users from crashing every time an operation takes the software to the limits of QuickDraw.
  4410. One way to approach this problem is to replace the lineProc bottleneck. All you need to do is to check the distance between the current pen position and the line’s end, and when the distance becomes too big (let’s say more than 32000) your procedure will call StdLine a couple of times, splitting the operation in two.
  4411. Replacing the bottlenecks is a very straightforward operation (which you are probably already using) and in most of the cases will only result in another level of indirection into StdLine but that will prevent your program from calling QuickDraw with parameters that are guaranteed to cause crashes.
  4412. Use crsrNew flag to unobscure cursor without mouse move
  4413. Date Written:  3/3/92
  4414. Last reviewed:  6/14/93
  4415. The Macintosh QuickDraw routine ObscureCursor hides the cursor until the next time the mouse is moved, but it isn’t affected by HideCursor or ShowCursor. Our application needs to use ObscureCursor while the user is typing but needs the cursor to be visible after no typing has occurred for a short period. How do we “undo” ObscureCursor, since we can’t rely on the user to move the mouse?
  4416. ___
  4417. The only way (besides actual mouse movement) to make an obscured cursor visible again is to convince the system that the mouse has moved. There’s no really good way to do this via Toolbox calls, so you’re going to have to do it the hard way and simply update the low-memory cursor information to tell the system the cursor moved (even though you don’t need to update the actual position).
  4418. To tell the system the cursor has changed location, simply set the crsrNew flag (a byte located at $08CE) to 1. When the system sees this byte is 1, it will assume the cursor has moved and redraw the unobscured cursor at the appropriate place (where it was all along), and reset CrsrNew, waiting for the mouse to move again.
  4419. Macintosh CalcMask and CopyMask code sample
  4420. Date Written:  2/27/92
  4421. Last reviewed:  6/14/93
  4422. I can’t get the black-and-white version of my lasso-type tool to work correctly with CalcMask and CopyMask. With CalcCMask it seems to work fine. What could I be doing wrong?
  4423. ___
  4424. CalcMask and CalcCMask are similar in that they both generate a 1-bit mask given a source bitmap. With CalcCMask, though, a pixMap can be used in place of the source bitmap; the seedRGB determines which color sets the bits in the mask image. An easy mistake to make is to forget that CalcCMask accepts a pointer to a bitmap data structure while CalcMask expects a pointer to the actual bit image. And unlike CalcCMask, which uses bounding Rects for the image’s dimensions, CalcMask uses the bitmap’s rowBytes and pixel image offsets to determine the bounding Rects for the image. A typical call to these routines would be
  4425.     BitMap source, mask;
  4426.     CalcMask (source.baseAddr, mask.baseAddr, source.rowBytes, 
  4427.               mask.rowBytes, source.bounds.bottom-source.bounds.top, 
  4428.               source.rowBytes>>1);
  4429.     CalcCMask (&source, &mask, &(*source).bounds, &(*mask).bounds, 
  4430.                &seedRGB, nil, 0);
  4431. One last thing to note when using CalcMask is that the width of the image is in words and not bytes. To learn more about these routines, see page 24 of Inside Macintosh Volume IV and page 72 of Inside Macintosh Volume V. Also, the Developer CD Series disc contains a sample, CalcCMask&CalcMask, that shows how to use both these routines.
  4432. Code for filling an area fully bounded by polygon
  4433. Date Written:  2/21/92
  4434. Last reviewed:  6/14/93
  4435. Currently, when a polygon is filled, an even-odd rule is applied to determine which areas of the polygon are to be filled. For our application, we also need to fill all the areas of the defined polygon. Is there a relatively easy way to accomplish this?
  4436. ___
  4437. There are many different ways to fill polygons, as you may know. If you do not want to use QuickDraw’s standard FillPoly routine, you’ll have to create your own. The following sample illustrates one technique that might be used to fill the area fully bounded by a polygon. It can be dropped right into the traffic light sample (sample.p) that ships with MPW as a replacement for its DrawWindow procedure. The green star is drawn using FillPoly and the black star is drawn using my filling technique that uses an offscreen bitmap and calcMask to fill in the poly the desired way, then CopyBits to transfer it to the onscreen port. The drawbacks of this method are that it is not as fast as writing a specialized poly routine; the benefits are that it’s small, fast enough for most operations, and can be used for more than just polygons.
  4438. {$S Main}
  4439. PROCEDURE DrawWindow(window: WindowPtr);
  4440. var        MyPoly:PolyHandle;
  4441.         MyRgn :RgnHandle;
  4442.         OffPort,OnPort:GrafPtr;
  4443.     Function    CreateOffport(VAR newOffscreen:grafPtr; 
  4444. inBounds:Rect):Boolean;
  4445.     var    SavePort,NewPort:Grafptr;
  4446.     begin
  4447.         GetPort(SavePort);
  4448.         NewPort:=GrafPtr(NewPtr(sizeof(grafport)));
  4449.         If MemError<>noErr then Begin
  4450.             CreateOffport:=false;
  4451.             EXIT(CreateOffport);
  4452.         END;
  4453.        
  4454.         OpenPort(newPort);
  4455.         With newPort^ do begin
  4456.             portRect :=Inbounds;
  4457.             RectRgn(ClipRgn,inBounds);
  4458.             RectRgn(visRgn, inBounds);
  4459.         End;
  4460.        
  4461.         With newPort^.PortBits DO BEGIN
  4462.             Bounds:=Inbounds;
  4463.             rowBytes:= ((inBounds.right-inBounds.Left+15) DIV 16) *2;
  4464.             baseAddr:= NewPtr(rowBytes 
  4465.                             * LONGINT(inBounds.Bottom-inBounds.Top));
  4466.         End;
  4467.         If MemError <>noErr THEN BEGIN
  4468.             SetPort(SavePort);
  4469.             ClosePort(newPort);
  4470.             DisposPtr(ptr(newPort));
  4471.             CreateOffport:=false;
  4472.           END
  4473.         ELSE  BEGIN
  4474.             EraseRect(inBounds);
  4475.             newOffscreen :=newPort;
  4476.             setPort(SavePort);
  4477.             CreateOffPort:=true;
  4478.         end;
  4479.     end;
  4480.    
  4481.     Procedure    KillOffPort(oldOffscreen :GrafPtr);
  4482.     Begin
  4483.         ClosePort(oldOffscreen);
  4484.         DisposPtr(OldOffscreen^.portBits.baseAddr);
  4485.         DisposPtr(ptr(OldOffScreen));
  4486.     End;
  4487. BEGIN
  4488.     If NOT (CreateOffPort(offPort,window^.portRect)) THEN Exit(DrawWindow);
  4489.     If NOT (CreateOffPort(onPort,window^.portRect)) THEN Exit(DrawWindow);
  4490.    
  4491.     SetPort(window);
  4492.     MyRgn:=NewRgn;
  4493.     OpenRgn;
  4494.         MoveTo(10,25);
  4495.         Lineto(70,25);
  4496.         Lineto(15,70);
  4497.         Lineto(40,10);
  4498.         Lineto(65,70);
  4499.         Lineto(10,25);
  4500.     CloseRgn(MyRgn);
  4501.     MyPoly:=OpenPoly;
  4502.         MoveTo(10,25);
  4503.         Lineto(70,25);
  4504.         Lineto(15,70);
  4505.         Lineto(40,10);
  4506.         Lineto(65,70);
  4507.         Lineto(10,25);
  4508.     ClosePoly;
  4509.     OffsetPoly(MyPoly,0,100);
  4510.     SetPort(OffPort);
  4511.     FramePoly(MyPoly);
  4512.     { Now "Fill the poly" the right way }
  4513.     CalcMask(    Offport^.portBits.BaseAddr,OnPort^.portBits.BaseAddr,
  4514.                 OffPort^.portBits.RowBytes, OnPort^.portBits.RowBytes,
  4515.                 OffPort^.portRect.bottom-OnPort^.portRect.Top,
  4516.                 OffPort^.portBits.RowBytes DIV 2);
  4517.     SetPort(OnPort);
  4518.     SetPort(Window); 
  4519.     If gStopped then
  4520.         CopyBits(    OnPort^.portBits, Window^.portBits,
  4521.                     OnPort^.portRect, Window^.portRect, srcCopy, NIL)
  4522.     ELSE
  4523.         CopyBits(    OffPort^.portBits, Window^.portBits,
  4524.                     OffPort^.portRect, Window^.portRect, srcCopy, NIL);
  4525.     IF gStopped THEN
  4526.       begin
  4527.         ForeColor(greenColor);
  4528.         FrameRgn(MyRgn);
  4529.       end
  4530.     ELSE
  4531.       begin
  4532.         ForeColor(greenColor);
  4533.         PaintRgn(MyRgn);
  4534.       end;
  4535.     ForeColor(blackColor);
  4536.     DisposeRgn(MyRgn);
  4537.     KillPoly(MyPoly);
  4538.     KillOffPort(Offport);
  4539.     KillOffPort(OnPort);
  4540. END; {DrawWindow}
  4541. Inside Macintosh Vol. V PICT opcode size should be fixed
  4542. Date Written:  1/22/92
  4543. Last reviewed:  2/28/92
  4544. The definition of PICT version 2 on pages 92-105 of Inside Macintosh Volume V says that the data size of the opcodes $001A and $001B is variable, but also that the data is an RGBColor. This is confusing, since the size of an RGBColor is fixed at six bytes. How can these two opcodes vary in the amount of associated data?
  4545. ___
  4546. Seems like you’ve run into a cut/paste problem. All the opcodes that refer to table 4 are new for Color QuickDraw. Also, most of them are variable in length, so the author simply had a standard notation for anything that was explained further in table 4 (page V-103). The information contained in table 4 is, in fact, accurate. The size information of several of the opcodes listed is not variable even though the preceding pages told you they were.
  4547. All you gotta do is believe table 4 and you will be fine.
  4548. PICTs with PostScript PICT comments and memory use
  4549. Date Written:  1/10/92
  4550. Last reviewed:  6/14/93
  4551. Why does my PICT (including dotted lines) use so much memory when drawn in MacDraw, and even more when drawn in SuperPaint? Do they include PicComments for PostScript?
  4552. ___
  4553. Your guess that it has to do with PicComments is quite right; both MacDraw and SuperPaint include a PostScript representation of the dotted (dashed) lines and some other graphic operations in the PICT, together with the QuickDraw commands. During printing, this allows the LaserWriter driver to take advantage of specific PostScript capabilities that are unavailable in QuickDraw, like primitives for dashed lines.
  4554. On the other hand, the PostScript representation for dashed lines is much shorter than the QuickDraw representation, which requires a (long, very long …) sequence of “ShortLine” opcodes. So, another piece of explanation for the large PICT size basically is that QuickDraw does not have facilities to describe dotted lines in an economic way.
  4555. SuperPaint also includes a copy of a proprietary dictionary, which adds substantially to the size of a PICT. On the other hand, the code that resides in that dictionary makes the picture’s PostScript representation that much better. Ultimately, WYSIWYG is the goal, and sometimes it takes a little extra code to make that happen. (Incidentally, the PostScript dictionary contained in pictures created by older versions of SuperPaint makes assumptions about the contents of the LaserPrep file which are not true for the recent versions of the LaserWriter driver. Documents containing such pictures will not print correctly any more.)
  4556. To determine the primitives that define other nonstandard QuickDraw objects found in drawing applications, you can use MPW’s DeRez function or a third-party utility such as Palomar Software’s PICT Detective on the resource PICT. These tools will provide the opcodes that define the PICT.
  4557. Where CopyBits looks for memory to use
  4558. Date Written:  1/3/92
  4559. Last reviewed:  1/27/92
  4560. Where does CopyBits look for the memory it needs?
  4561. ___
  4562. CopyBits checks the stack to determine if there is enough stack space for it to copy the whole image, which in some cases may be roughly up to 5 extra rowbytes of special effects per row, depending on what special effects such as dithering or scaling are being used. If there is not enough stack space for the whole image, CopyBits then tries for half the image, and keeps halving until it gets down to one row of the image (plus the room for the special effects rows). If there is not enough stack space for one row of the image, then CopyBits tries to allocate temporary memory.
  4563. Before allocating temporary memory, CopyBits checks if the temporary memory traps are available. (They are available under both System 6 MultiFinder and System 7.) If the traps are available, CopyBits tries to allocate a 256K byte buffer for use as a “fake” stack. (CopyBits used to try for a 64K block, but this has been changed, and it may change again.) If this succeeds, then all is well and the image is copied. If the temporary memory traps do not exist, or if CopyBits cannot allocate a 256K buffer, then the image is not copied and CopyBits returns.
  4564. CopyBits does not check in the application heap for free memory, at least not for its work buffer. For its work buffer it will only use the stack, and after that it resorts to temporary memory, if available. There are some circumstances that may cause memory allocations in the application heap, but this memory is not used for CopyBits’s image buffer.
  4565. Also, please note that the implementation of CopyBits is subject to change in future versions of QuickDraw.
  4566. GrafPort patStretch: valid values
  4567. Date Written:  12/19/91
  4568. Last reviewed:  6/14/93
  4569. I’d like to know more about that PatStretch field inside a GrafPort or CGrafPort. If I stuff a values in PatStretch(4) then nothing happens; prints look the same, even using a standard bottleneck. Please tell me how I can get this to work.
  4570. ___
  4571. PatStretch only works with values of 2 or 3. With any other value, it defaults to no stretching. The “2” case was created because of the ImageWriter (72->144 dpi) situation. The “3” case was added to support the ImageWriter LQ and the AppleFax modem.
  4572. So why wasn’t a “4” (72->300 dpi) handler added for the LaserWriter driver? Good question. Somehow or other it was decided that pattern stretching for the LaserWriter driver would be done completely by the driver itself. The LaserWriter driver actually does pattern stretching by using a pattern 4 times as large, rather than 4.17. In other words, it really scales the 72 dpi pattern to 288 dpi rather than 300 dpi. You may want to take a similar approach, since you’d only have to work with whole numbers this way.
  4573. So, if you want to do 4-times pattern stretching, you must scale the pattern yourself. If you copy the original pattern into an area that’s twice as wide and twice as tall and use that, you should be all set. You’ll need to use PrGeneral to set the printer to the appropriate resolution and Copybits to copy the pattern into the object that needs to be filled, using the “cookie cutter” approach to fill the object.
  4574. X-Ref:
  4575. Inside Macintosh Volume I, page I-150
  4576. How to tell whether GetPictInfo is available
  4577. Date Written:  12/16/91
  4578. Last reviewed:  6/14/93
  4579. How do you determine whether the Picture Utilities Package function GetPictInfo is available? Gestalt doesn’t seem to have the right stuff!
  4580. ___
  4581. To determine whether the GetPictInfo routine is available, check the system version number with the Gestalt function. GetPictInfo is available in system software version 7.0 and later. Use the Gestalt selector gestaltSystemVersion to determine the version of the system currently running. Usually it’s best not to rely on the system version to determine whether features are available, but in this case, it’s the only way to determine whether the Picture Utilities Package is available.
  4582. For example, the following C function will determine whether the GetPictInfo call is available:
  4583. #include <GestaltEQU.h>
  4584. Boolean IsGetPictInfoAvail()
  4585. {
  4586.   OSErr  err;
  4587.   long  feature;
  4588.   err = Gestalt(gestaltSystemVersion,&feature);
  4589.   /* Check for System 7 and later */
  4590.   return (feature >= 0x00000700);
  4591. }
  4592. In Inside Macintosh Volume VI, see page 3-42 for information on using Gestalt to check the system version number, and see page 18-3 for information on the Picture Utilities Package.
  4593. Detecting whether application window is partially hidden
  4594. Date Written:  9/26/92
  4595. Last reviewed:  6/14/93
  4596. We draw directly to the screen to gain the fastest possible animation speed, and when we need compatibility—such as when windows overlap or for multiple screens—we do use CopyBits. How do we tell whether the window is hidden or that the visible part is not rectangular?
  4597. ___
  4598. If your window is covered partially by another applications window or if your layer has been hidden by the process menu, the visRgn of your window’s grafport will not be the portRect anymore. (Keep in mind that if you scroll by modifying the portRect of the grafport, then you’ll have to do a more complex calculation...) Here is a small Pascal routine that returns this information:
  4599. Function UseCopyBits(thePort:grafptr):Boolean;
  4600. begin
  4601.    
  4602.      UseCopyBits:= NOT( (thePort^.VisRgn^^.rgnSize=10) and
  4603.         (thePort^.visRgn^^.RgnBBox=thePort^.PortRect) );
  4604. end;
  4605. The rect strucRgn^^.rgnBBox will be zero for a visible window if the system 
  4606. has hidden the application.
  4607. CopyBits bug and workaround
  4608. Date Written:  6/26/91
  4609. Last reviewed:  6/14/93
  4610. Has anyone run across what I’m told is a bug in CopyBits? It works like this: In the deep, dark workings of CopyBits, some routine tries to read the two bytes preceding the baseAddress of the source PixMap. If the baseAddress is at the start of a card’s NuBus space and there isn’t a card filling the adjacent space, this causes a bus error! Has anyone found a good workaround?
  4611. ___
  4612. The short answer is: you’re right. QuickDraw inadvertently reads from memory below the base address of a pixmap. The workaround is to place the video base address 32 bytes into the slot memory space for the card; if the card you’re using doesn’t have this workaround, there’s nothing you can do other than making sure there’s a card in the next-lower slot.
  4613. Macintosh animation samples
  4614. Date Written:  11/6/91
  4615. Last reviewed:  6/14/93
  4616. Do you have an example of flicker-free animation on the Macintosh?
  4617. ___
  4618. We have some good stuff that’s written in MPW Pascal. It’s DTS Sample Code #16, OffSample, and this uses some routines defined in DTS Sample Code #15, OffScreen. Also, the System 7.0 CD sample code folder contains a smaller sample called “GMonde” that uses GWorlds.
  4619. System 7 QuickDraw DrawText performance
  4620. Date Written:  11/4/91
  4621. Last reviewed:  11/27/91
  4622. We’ve noticed that using DrawText is much slower in System 7, especially when drawing in color (anything other than black on white). What can be done to restore the drawing speed to System 6 levels?
  4623. ___
  4624. A QuickDraw function like DrawString or DrawText will be slower under certain circumstances in System 7 than System 6. Specifically, if you are drawing in srcCopy mode and you colorize the text—that is, foreground color is not black and background color is not white (Inside Macintosh Volume VI, page 17-16)—then QuickDraw really slows down as you have noticed. Sometimes, the speed of drawing is 6 times as slow as System 6.
  4625. The cause of this slowness is a known System 7 bug. The bug has concerned the engineers greatly and will be responded to in an appropriate manner in the future.
  4626. There are a few workarounds: One, you can avoid using the srcCopy mode and use the default srcOr mode instead. However, this is not a real workaround, since you may have essential reasons to use srcCopy. The other option is to create an offscreen pixmap or GWorld and perform a DrawText with srcOr to this GWorld with colorization. Then, you can perform a CopyBits from the offscreen to the screen with srcCopy mode and no colorization. Using CopyBits will not cost you much time. Again, this is a workaround and is not ideal. 
  4627. The srcOr is a bit slower than in System 6.0.x, but it does not have a bug; rather it is a side effect of system enhancements. The slow speed is a trade-off taken to receive the host of other benefits.
  4628. Updating Macintosh cursor without mouse competition
  4629. Date Written:  6/12/91
  4630. Last reviewed:  6/14/93
  4631. How can I programmatically move the Macintosh mouse without the real mouse interfering?
  4632. ___
  4633. The real answer to your question is twofold: First, you can do exactly what you want to do with the sample included below. However, this is not a good thing to do, it would be better if you took the solution used in Apple’s Guided Tour disks: Always hide the cursor and then decouple the cursor from the mouse. Then, instead of using the system’s cursor, simply draw your own “cursor” using QuickDraw and treat it as a little animated bitmap on the screen. This avoids all the problems that you have with the mouse competing. (Apple does update the mouse globals with the mouse position so that other things function correctly.)
  4634. Now, as promised, here is the way to do what you want using the real cursor. As you have discovered, setting the crsrCouple variable to false prohibits the mouse from affecting the cursor; unfortunately, it also prohibits the jcrsrTask routine from drawing the cursor. The solution to this is to set crsr couple to true, call the cursor drawing routine jCrsrTask yourself, and then set the crsrCouple variable to false, as shown below:
  4635. procedure callcrsr;
  4636.               inline $2078 ,$08EE ,$4E90;
  4637. {            move.L    jcrsrTask,A0
  4638.             jsr    (A0)                            }
  4639. Procedure FudgeMouse;
  4640. type    PointPtr=^Point;
  4641. var        RawMouse:PointPtr;
  4642.         MTemp:PointPtr;
  4643.         RandPt:Point;
  4644.         CrsrNew:ptr;
  4645.         CrsrCouple:ptr;
  4646.         fred:Longint;
  4647.        
  4648. begin
  4649.         RawMouse:=PointPtr($82C);
  4650.         MTemp:=PointPtr($828);
  4651.         CrsrNew:=ptr($8CE);
  4652.         CrsrCouple:=ptr($8CF);
  4653.         RandPt:=RawMouse^;
  4654.         repeat
  4655.             RandPt.h:=RandPt.h+1;
  4656.             RandPt.V:=RandPt.v+1;
  4657.             RawMouse^:=RandPt;
  4658.             MTemp^:=RandPt;
  4659.             CrsrNew^:=1;
  4660.             CrsrCouple^:=1;
  4661.             callCrsr;
  4662.             crsrCouple^:=0;
  4663.             repeat until fred<tickCount;
  4664.             fred:=tickCount+3;
  4665.         until Button;
  4666.         crsrCouple^:=1;
  4667. end;
  4668. Techniques for graying Macintosh text
  4669. Date Written:  6/3/91
  4670. Last reviewed:  6/14/93
  4671. How do I draw grayed-out text on the Macintosh, like the text for disabled buttons or menu items?
  4672. ___
  4673. There are currently two different kinds of grayed text: First, there’s “patterned” gray, where every other dot is missing. This really only looks good with Chicago or other heavy fonts and was always used for graying out menus and controls in system software through 6.0.x, and is still used in 7.0 when the screen is set to less than 4 bits deep. This is done by first drawing the text in a normal, srcCopy transfer mode. Then a gray rectangle is drawn over the text using the patBic mode. This “erases” half the bits in the text, and is rapid enough that there is very rarely any flicker.
  4674. The second kind of text is the actually gray text, which is used in System 7 on screens that are 4 bits deep or deeper for menus, controls, and other grayed text. To draw this text, just call GetGray (as documented on page 17-27 of Inside Macintosh Volume VI) to get an appropriate gray. Then draw the text in that color.
  4675. Use srcOr instead of srcCopy for Macintosh text drawing
  4676. Date Written:  6/4/91
  4677. Last reviewed:  10/9/91
  4678. DrawText with srcCopy takes six times as long as with srcOr now that my Macintosh is running System 7. Why is this so slow? Is this a bug in System 7?
  4679. ___
  4680. It’s true that srcCopy is slower than srcOr when handling text, especially in color mode. This loss in speed occurs because CopyBits is a lot smarter than it used to be. It can handle foreground and background colors a lot better, but that improvement came at the cost of speed. Our recommended method for drawing text is to erase before drawing, and use srcOr to draw, not srcCopy. Alternatively, you could draw colorized text in srcOr mode off screen and then use CopyBits to draw it on the screen in srcCopy mode without colorization.
  4681. Code for reversing Macintosh PICT images
  4682. Date Written:  3/4/91
  4683. Last reviewed:  6/14/93
  4684. Is there a simple way to put PICT images up in mirror image format, or is there sample code showing how to flip an offscreen bitmap?
  4685. ___
  4686. There is no easy way to do this, nor do we have sample code showing how to flip an offscreen bitmap. Indeed, the best way to do what you want is to draw it to an offscreen pixel map and reverse it.
  4687. If you are using Color QuickDraw, always draw it to an 8-bit-per-pixel offscreen bitmap, and then the reverse is a very simple task. Here is some sample Pascal code that might roughly do what you want, with the following assumptions:
  4688.     1. You are going to add error checking where appropriate.
  4689.     2. Rowbytes correspond exactly to pixel width of the port.
  4690.     3. The port is 8 bits deep.
  4691.     4. You add the code to make this sketch work.
  4692.     5. The origin of your offscreen port is (0,0).
  4693. Procedure FlipScanLine(theV:Integer; thePort:cGrafPtr);
  4694. { Given any scan line number in the indicated port, this routine will flip }
  4695. { that scan line horizontally. This routine assumes that you have made     }
  4696. { sure that scan line theV exists. }
  4697. type ScanLn=Packed Array [0..0] of Byte;
  4698.    ScanPtr=^ScanLine;
  4699. var thePixMap:PixMapPtr;
  4700.    Index,Size:Integer;
  4701.    ThisScanLine:ScanPtr;
  4702.    TempPixel:Byte;
  4703. Begin
  4704.  thePixMap:=thePort^.PortPixMap^;
  4705. { First create a pointer to the scan line we are currently reversing. }
  4706.  ThisScanLine:=ScanPtr(thePixMap^.BaseAddr);
  4707.  ThisScanLine:=ScanPtr(ord4(ThisScanLine)+(thePixMap^.RowBytes*theV));
  4708. { Now simply reverse all the bytes. }
  4709. { The scan line is simply an array [0..RowBytes] of Byte, and since this is }
  4710. { 8 bits per pixel, each one is a single pixel.}
  4711.  Size:=thePixMap^.RowBytes;
  4712.  For Index:=0 to (Size div 2) do
  4713.   begin
  4714.    tempPixel:=ThisScanLine^[Index];
  4715.    ThisScanLine^[Index]:=ThisScanLine[Size-Index-1];
  4716.    ThisScanLine^[Index]:=tempPixel;
  4717.   end;
  4718. end;
  4719. This same procedure can be used also to swap a 1-, 2- or 4-bit-per-pixel pixmap if you add a function that accepts a byte and swaps the pixels in it.
  4720. Using dithered drawing mode with QuickDraw
  4721. Date Written:  11/28/90
  4722. Last reviewed:  12/19/90
  4723. When I draw a 32-bit Macintosh PICT image from a file to an 8-bit port via an offscreen GWorld, I use dither mode in the CopyBits call and the results are quite impressive. If there is not enough memory to allocate the GWorld, I draw the image directly to the port. But since there does not seem to be any way to tell QuickDraw to use dithered drawing mode, the image looks horrible.
  4724. Do you have any suggestions? I have installed bottleneck procs to allow DrawPicture to get its data from the file instead of the handle in memory. Is there a way, while in the bottlenecks, to find the CopyBits call that comes from the picture and force it to use dithered mode instead of source mode? I don’t want to try and parse the PICT myself, but I thought that maybe a QuickDraw global could be modified in my StdBits proc to force dithered drawing for that operation only?
  4725. ___
  4726. You can install a StdBits or bitsProc bottleneck procedure to get all the CopyBits calls when the picture is being played back. One of the parameters to the StdBits call is the mode. You can install a procedure that saves the current mode, and then passes ditherMode to the original StdBits proc. This is all you should need to do. It’s been done here so we know it works, only not in any form that can be sent to you as sample code at this time.
  4727. Using PicComments to rotate text
  4728. Date Written:  11/28/90
  4729. Last reviewed:  12/19/90
  4730. I have a PostScript routine (using TextBegin/TextEnd) to generate bitmapped rotated text on the screen (which can be later printed on QuickDraw printers). Why do I get duplicate text? I get both bitmapped rotated text and PostScript rotated text when I print on the LaserWriter II, and both bitmapped rotated text and horizontal text on the ImageWriter. When I make a machine dependent check (check type of printer) and call the proper printing procedure, it works fine. Because of the speed and memory considerations of generating the rotated bitmapped text (especially at 300 dpi), is there a way to ensure that the printer will use the PostScript BEFORE generating the bitmap?
  4731. ___
  4732. We will use the following Macintosh PicComments to hide your QuickDraw calls from the LaserWriter, but the ImageWriter will use them:
  4733. PostScriptBegin
  4734.  >> Put your CopyBits and QuickDraw calls to image your rotated
  4735.  >> bitmapped text here....
  4736. PostScriptEnd
  4737. By wrapping your QuickDraw code within the PostScriptBegin and PostScriptEnd PicComments, the code will be ignored by the LaserWriter, but the ImageWriter will use the QuickDraw calls. Basically, the PostScriptBegin and PostScriptEnd PicComments tell the LaserWriter driver to turn “off” QuickDraw. In the ImageWriter case, the ImageWriter does not understand the PicComments. Therefore, it will use the QuickDraw calls to create and image your bitmapped text. 
  4738. Now, we need to use the rotation PicComments to rotate the text on the LaserWriter, but have the ImageWriter ignore the code:
  4739. Rect  zeroRect;
  4740. SetRect (&zeroRect, 0, 0, 0, 0);
  4741. TextBegin
  4742. TextCenter
  4743.       ClipRect (&zeroRect);
  4744.       >> Draw your text to be rotated on the LaserWriter....
  4745.       ClipRect (&rPageRect);
  4746. TextEnd
  4747. Wrapping your text drawing call(s) between the ClipRect calls will ensure that the text is drawn only on the LaserWriter. Setting the ClipRect to zero tells the ImageWriter to ignore all QuickDraw calls until the ClipRect is reset to something “real” (actually, a zero ClipRect prevents QuickDraw from drawing anything). After we have completed drawing the rotated text, we reset the ClipRect to the dimensions of rPage (that is, rPage is the image-able area of the currently selected printer—see Inside Macintosh Volume II, page 150). This will allow all of your normal drawing to continue on the ImageWriter and LaserWriter. If you did not reset the ClipRect after the TextEnd call, nothing would be drawn on the ImageWriter or LaserWriter.
  4748. Why grafPort’s clipRgn should be changed before OpenPicture
  4749. Date Written:  11/1/90
  4750. Last reviewed:  12/19/90
  4751. On page 189 of Inside Macintosh Volume I, in the QuickDraw chapter’s description of OpenPicture, is the following warning: “A grafPort's clipRgn is initialized to an arbitrarily large region. You should always change the clipRgn to a smaller region before calling OpenPicture, or no drawing may occur when you call DrawPicture.” The “arbitrarily large” clipping region rectangle is set to -32767,- 32767,32767,32767 (top, left, bottom, right) for new ports. This is the largest rectangle possible. If this is not a "valid" clipping rectangle for pictures, what is? Is there some specific limit to the size of the clipping rectangle? Does it depend on either available memory or the size of the picture?
  4752. ___
  4753. Inside Macintosh’s warning is based on truth but it’s incomplete. It didn’t actually say that this rectangle is invalid as a clipping region, because this is in fact a perfectly valid clipping region. But, you could run into problems if you use this as a clipping region when creating a QuickDraw picture. It’s not a matter of available memory or size; it’s a simple matter of 16-bit signed integer overflow and underflow.
  4754. When you open a picture, the current clip region is recorded in the picture (this wasn’t necessarily true in some early versions of QuickDraw). When you draw the resulting picture using the picture’s picFrame as the destination rectangle, there won’t be any problems. But if you use a destination rectangle that’s larger than the picFrame, QuickDraw scales everything in the picture proportionately, including the clip region. If you allowed the default clip region to be recorded into the picture, then its rgnBBox, already as large as possible, will be made even larger. That means that the -32767 coordinates might wrap around to the positive number range, and the 32767 coordinates might wrap around to the negative number range. This leaves you with an empty clip region. Nothing at all gets drawn when the current port’s clip region is empty.
  4755. If the destination rectangle is smaller than the picture’s picFrame, you won’t have any problems because the default clip region will be made smaller, and that’s no problem.
  4756. This is why Inside Macintosh suggests that you make the clip region smaller than the default clip region before opening a picture. By doing this, you’re almost guaranteed that the clip region won’t get scaled to the point that it turns inside out. What size should you make it? Small enough so that the risk of the clip region’s coordinates being scaled out of QuickDraw coordinate space is minimal. I usually just set the clip region to the picFrame of the picture. It’s hard to go wrong this way.
  4757. Calling InitCursor instead of SetCursor
  4758. Date Written:  10/23/90
  4759. Last reviewed:  6/14/93
  4760. Is it legal to call InitCursor instead of SetCursor(arrow) when I want to set the cursor to an arrow (after my normal one-time program initialization code, in my UpdateCursor routine)? The only reason I'd want to do such a skanky thing is to save code. Calling a trap with no parameters is less code than one with parameters. What, exactly, if anything, does InitCursor do besides setting the cursor to an arrow and setting the cursor level to zero?
  4761. ___
  4762. There's no problem at all with this, as long as you are aware that the hidden, busy, and obscured states are cleared when you call InitCursor, so if the cursor was hidden or obscured for good reason it'll suddenly reappear. It also gets the arrow from QuickDraw, of course, but that's not a problem.
  4763. Macintosh PICT-to-PostScript conversion
  4764. Date Written:  8/3/90
  4765. Last reviewed:  10/8/91
  4766. How do I convert PICT format data to PostScript in my printer driver?
  4767. ___
  4768. Converting PICT files to PostScript involves a detailed understanding of both bitmaps (or pixmaps) and the graphics state in PostScript, which is a data structure defining the context in which other graphic operators in PostScript execute. If you don’t know PostScript, the following manuals are a must:
  4769. •    PostScript Language Tutorial and Cookbook (Addison-Wesley) is an introduction to PostScript. • PostScript Language Reference Manual (Addison-Wesley).
  4770. •    PostScript Language Program Design (Addison-Wesley) details designing efficient PostScript programs. It has a lot of useful sample programs on topics like writing a print spooler.
  4771. You need to convert all the QuickDraw operations in a PICT to corresponding PostScript operations. To get a feel for this conversion, you can analyze the PostScript dump from a LaserWriter to see how it converts a PICT to PostScript. Under System 6.x, a PostScript dump can be obtained by pressing Command-K while printing. Under System 7.0, you can get a dump by selecting the PostScript File option in the Print dialog.
  4772. Some areas of QuickDraw, such as transfer modes, do not have a correspondence in PostScript. The PostScript imaging model is designed so that all areas of a page affected by an image are marked as if with opaque paint. Using image masks can help. See the Graphics chapter in the PostScript reference manual.
  4773. PICT-to-PostScript conversion can be a long process, especially if one is unfamiliar with PostScript. Using the above books and the PostScript dump from the LaserWriter (but ONLY as a general guide) should help.
  4774. Sending PostScript via PostScriptHandle PicComment
  4775. Date Written:  5/1/90
  4776. Last reviewed:  10/9/91
  4777. If I use the PostScriptHandle PicComment to send PostScript code to the LaserWriter driver, do I need to open a picture and then draw the picture to the driver, or can I just use the PicComment with no picture open while drawing to the printer’s grafPort?
  4778. ___
  4779. You don’t need to create a picture with your PicComment in it and draw the picture to the driver. The best method for sending PostScript code to the LaserWriter is to use the PostScriptHandle PicComment documented in the Macintosh Technical Note “Optimizing for the LaserWriter—Picture Comments,” as shown below.
  4780. PrOpenPage(...)
  4781. { Send some QuickDraw so that the Printing Manager gets a }
  4782. { chance to define the clipping region. }
  4783. PenSize(0,0); 
  4784. MoveTo(0,0);
  4785. LineTo(0,0); 
  4786. PenSize(1,1); 
  4787. PicComment(PostScriptBegin, 0, NIL);
  4788. { QuickDraw representation of graphic. }
  4789. MoveTo(100, 100);
  4790. LineTo(200, 200);
  4791. { PostScript representation of graphic. }
  4792. thePSHandle^^ := '100 100 moveto 200 200 lineto stroke';
  4793. PicComment(PostScriptHandle, GetHandleSize(thePSHandle),
  4794.         thePSHandl);
  4795. PicComment(PostScriptEnd, 0, NIL);
  4796. PrClosePage(...)
  4797. The above code prints a line on any type of printer, PostScript or not. The first MoveTo/LineTo combination is required to give the LaserWriter driver a chance to define a clipping region. The LaserWriter driver replaces the grafProcs record in the grafPort returned from PrOpenDoc. In order for the LaserWriter driver to get execution time, you must execute a QuickDraw drawing routine that calls one of the grafProcs. In this case, the MoveTo/LineTo combination calls the StdLine grafProc. When StdLine executes, it notices that the grafPort has been reinitialized, and therefore initializes the clipping region for the port. Until the MoveTo/LineTo combination is executed, the clipping region for the port is set to (0,0,0,0). If PostScript code is sent via the PostScriptHandle PicComment before executing any QuickDraw routines, all PostScript operations will be clipped to (0,0,0,0).
  4798. The next thing that’s done is to send the PostScriptBegin PicComment. This comment is recognized only by PostScript printer drivers. When the driver receives this comment, it saves the current state of the PostScript device (by executing the PostScript gsave operator), then disables all QuickDraw drawing operations. This way, the QuickDraw representation of the graphic will be ignored by PostScript devices. In the above example, the second MoveTo/LineTo combination is executed only on non-PostScript devices.
  4799. The next PicComment is PostScriptHandle, which tells the driver that the data in thePSHandle is to be sent to the device as PostScript code. The driver then passes this code unchanged to the PostScript device for execution. The PostScriptHandle comment is recognized only by PostScript printer drivers.
  4800. The last PicComment, PostScriptEnd, tells the driver to restore the previous state of the device (via a PostScript grestore call), and to enable QuickDraw drawing operations.
  4801. Since most PicComments are ignored by QuickDraw devices, only the QuickDraw representation is printed. Since PostScriptBegin tells PostScript drivers to ignore QuickDraw operations, only the PostScript representation is printed on PostScript devices. This is a truly device-independent method for providing both PostScript and QuickDraw representations of a document.
  4802. Macintosh QuickDraw region quirks
  4803. Date Written:  1/1/90
  4804. Last reviewed:  11/21/90
  4805. I’m working with regions, and I’m having problems with Macintosh QuickDraw trashing the heap and crashing, even though my regions are under 32K.
  4806. ___
  4807. There are some quirks in the current version of QuickDraw. Here are some the commonly-encountered problems:
  4808. 1.    When doing operations which use more than one region, sduch as UnionRgn, DiffRgn, XorRgn, or SectRgn, the sum of the sizes of the source regions must be less than 32K, regardless of the size of the resulting region.
  4809. 2.    FrameRgn will fail if it tries to frame a region bigger than 16K.
  4810. 3.    If CloseRgn fails, the internal region data is already corrupt; there is nothing you can do to recover. CloseRgn will also fail if there isn’t at least a 32K block of free space available.
  4811. Here are some workarounds:
  4812. 1.    Keep regions small and not too complex. Keep track of the sizes of all regions so you can check the SUM of the sizes before calling a routine that has a 32K limit.
  4813. 2.    Keep 32K free, or allocate a 32K block and release it just before calling CloseRgn.
  4814. Apple is working on these problems and expects to fix them in future versions of QuickDraw.
  4815. How to get Macintosh QuickDraw arc endpoints
  4816. Date Written:  1/1/90
  4817. Last reviewed:  6/14/93
  4818. Is there a way to obtain the endpoints of an arc drawn by the Macintosh QuickDraw arc routines, such as FrameArc and PaintArc?
  4819. ___
  4820. Given a rectangle R which frames the arc you wish to draw, convert your angles to an absolute coordinate system, where three o’clock is 0 degrees and 12 o’clock is 90 degrees.
  4821. Now, let:
  4822.     x = .5 (+ or -) (R.right - R.left)
  4823.     y = .5 (+ or -) (R.bottom - R.top)
  4824. The endpoint of the curve will be defined by:
  4825.     EndPoint.h = x (+ or -) cos(ang);
  4826.     EndPoint.v = y (+ or -) sin(ang);
  4827. h & v are relative to center of rectangle R
  4828. This calculates only the upper endpoint of the arc, but you can easily calculate the other endpoint using the same formula by calculating the absolute angle for the start point and applying the same formula.
  4829. Here is a subroutine which illustrates the algorithm, in ThinkSpeed Pascal:
  4830. { DrawCurve: draw an arc from 0 degrees until the point defined }
  4831. { by 'angle'. At that point draw a 4 by 4 crosshair. }                        
  4832. procedure DrawCurve (frame : Rect; angle : integer);
  4833. var
  4834.   x, y : integer;
  4835.   xr, yr : extended;
  4836.   rad : extended;
  4837. begin
  4838.   { Convert angle to radians }
  4839.   rad := (90 - angle) / 180 * 3.14159;
  4840.   { Find end point }
  4841.   xr := (frame.right - frame.left) * cos(rad) / 2;
  4842.   yr := (frame.bottom - frame.top) * sin(rad) / 2;
  4843.   x := (frame.right + frame.left) / 2 + Num2Integer(xr);
  4844.   y := (frame.bottom + frame.top) / 2 + Num2Integer(yr);
  4845.   { Draw crosshair }
  4846.   MoveTo(x - 4, y);
  4847.   LineTo(x + 4, y);
  4848.   MoveTo(x, y - 4);
  4849.   LineTo(x, y + 4);
  4850.   { Draw arc }
  4851.   FrameArc(frame, 0, angle);
  4852. end;
  4853. QD 510 - Color Manager Q&As
  4854. QuickDraw    
  4855. Revised by:    Developer Support Center    September 1993
  4856. Written by:    Developer Support Center    October 1990
  4857. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  4858. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  4859. Using ResEdit to get Apple icon RGB values
  4860. Date Written:  1/7/92
  4861. Last reviewed:  6/14/93
  4862. I am trying to find the RGB values for Apple's standard icon colors. I can’t find this information in any documentation. Is this information available?
  4863. ___
  4864. While the RGB values for the standard Apple icon colors (and other standard palette colors) are not explicitly documented, they are easy to obtain with ResEdit 2.1.1. In any resource file, create and open a new 'pltt' resource. Choose Load Colors from the pltt menu and pick Apple Icon Colors, and a standard palette will be created. Selecting a color will reveal its component values.
  4865. ResEdit 2.1.1 is available on the latest Developer CD Series disc and from APDA.
  4866. Macintosh Color Manager versus Palette Manager
  4867. Date Written:  1/1/90
  4868. Last reviewed:  6/14/93
  4869. When should the Macintosh Color Manager be used and when should the Palette Manager be used?
  4870. ___
  4871. The Palette Manager is by far the friendlier and more versatile of the two if your application uses different colors than the default system colors. It provides all the functionality you need to customize and animate the colors in your application. You shouldn’t ever need to use the Color Manager unless you require custom color search and complement functions. When using the Palette Manager, applications will maintain their respective color environments safely as they move back and forth from foreground to background, and from one screen to another. Accomplishing this with the Color Manager calls is not worth the effort or very safe. For additional information, see the Palette Manager chapter in Inside Macintosh Volumes V and VI.
  4872. QD 515 - Color QuickDraw Q&As
  4873. QuickDraw    
  4874. Revised by:    Developer Support Center    September 1993
  4875. Written by:    Developer Support Center    October 1990
  4876. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  4877. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  4878. New Q&As in this Technical Note:
  4879. Color QuickDraw not available to 68000 Macintosh models
  4880. Check ‘cicn’ ID if menu icons are tiny
  4881. Color QuickDraw and large pixmaps
  4882. Color QuickDraw not available to 68000 Macintosh models
  4883. Date Written:   2/4/93
  4884. Last reviewed: 3/17/93
  4885. Inside Macintosh Volume VI says Color QuickDraw is built into System 7, but when I use Gestalt to check for Color QuickDraw on a Macintosh PowerBook 100 running System 7, the call returns 0 in QDversion. What’s wrong?
  4886. ___
  4887. The Color QuickDraw routines were written in 68020 assembly, meaning that only Macintosh models with 68020 and later CPUs have access to Color QuickDraw. Models such as the Macintosh SE, Macintosh Classic, and PowerBook 100 can use only Classic QuickDraw. However, this isn’t such a bad thing because the processing power required to run Color QuickDraw would be an enormous burden on the 68000 machines.
  4888. The bulk of Color QuickDraw routines reside in the larger ROMs of models using the 68020 and greater CPUs, thus taking the burden away from system software. However, if changes have to be made to Color QuickDraw (usually in the form of patches) they reside in system software.
  4889. Check 'cicn' ID if menu icons are tiny
  4890. Date Written:   2/16/93
  4891. Last reviewed: 7/2/93
  4892. The icons that appear in our application’s menu lists are very, very small. It looks like they’re 8 x 8 (scaled) instead of the standard 16 x 16. Can you tell from our test code why this is happening?
  4893. ___
  4894. This was a wild one! What’s causing the weird behavior is that you have a 'cicn' resource with ID = 256 that’s smaller than 32 x 32. When the MDEF finds such an icon, it uses it to size the area to use for the menu icons. So, for your application the solution is either to change the 'cicn' to be larger (32 x 32) or to give it a different ID.
  4895. Color QuickDraw and large pixmaps
  4896. Date Written:   3/11/93
  4897. Last reviewed: 6/24/93
  4898. Somewhere in QuickDraw, a routine is using the 14th bit of the rowBytes field (the 15th is used to differentiate a pixmap from a bitmap) and it really shouldn’t. This is a problem now that it’s so easy to create large pixmaps of 4096 32-bit pixels or more. What’s causing the problem and what’s the recommended solution for handling large pixmaps?
  4899. ___
  4900. This is a long story. It’s described in Inside Macintosh Volumes V and VI but we’ll summarize it here.
  4901. Color QuickDraw allows you to pass one of three addresses to CopyBits: the address of a bitmap, the address of a pixmap, or the address of the pixmap handle of a port. The first two conditions (bit and pixmap) are determined by bit 15 of rowBytes: if the bit isn’t set, the address points to a bitmap; otherwise, it points to a pixmap. The third case is the problem here. A color port’s portVersion field is expected to be set to 0xC000, so after deciding it’s dealing with a possible pixmap CopyBits checks bit 14 and if it’s set it assumes it got the address of the pixmap handle in a CGrafPort and proceeds to dereference it in order to get the real address of the pixmap.
  4902. Today’s applications have trouble with this because they must either refuse to create pixmaps as big as users want or cause crashes by confusing CopyBits into dereferencing the base address of the pixmap if rowBytes exceeds the established limit of less than 0x4000.
  4903. Engineering is studying future solutions. It’s possible that a future QuickDraw release will support pixmap with a rowBytes constant value indicating that the real rowBytes is contained in the planeBytes field instead. You might think of cases where this is also going to cause problems but the problems probably are less important than the limitation being overcome.
  4904. For the present, the solution depends on the conditions under which the problem affects you. If you’re writing an application, the solution could be to patch CopyBits and call DrawPicture. When CopyBits is called while a picture is being drawn the source is a pixmap; if rowBytes is too big, your application could split the job banding the image vertically until the resulting rowBytes values fall within range. With a little debugging it would be possible to find where CopyBits calls the bit/pixmap/port checking routine and bypass that, given that the actual routine doing the blitting doesn’t have problems dealing with pixmaps of less than 0x8000 rowBytes.
  4905. Another possibility is to call StdBits directly since it doesn’t mind dealing with larger than legal rowBytes. The problem here is that the destination is implied and the application has to make sure that everything is all right. Also if the destination spans multiple devices the application must divide the task, targeting each device at the time. See the DeviceLoop procedure in Inside Macintosh Volume VI for ideas on this.
  4906. To recap: The limitation of rowBytes is becoming increasingly painful, now that applications can easily create pixmaps (and PICTs) that exceed the limit of 0x4000. It’s possible for an application to patch CopyBits in order to work around this limitation but you have to decide what is appropriate for each set of conditions.
  4907. Animation speed on the Macintosh
  4908. Date written:  1/18/93
  4909. Last reviewed:  4/1/93
  4910. How can I get reasonably fast animation on Macintosh models? So far, I’ve created off-screen pixmaps with the image and mask, and an extra off-screen pixmap for use in restoring the original picture. However, CopyPix is still too slow. I had to write my own CopyPix routine in assembly, which works great. But I can’t help wondering how Apple expected fast animation to be accomplished.
  4911. ___
  4912. You’re certainly right that the way to increase performance is by off-screen drawing and QuickDraw’s CopyBits procedure. The key information that’s useful to you is in the Macintosh Technical Note “Of Time and Space and _CopyBits.” This tech note covers some of the factors affecting CopyBits and what can be done to improve the speed of calling CopyBits.
  4913. Just to mention some of the factors that might improve the speed of calling CopyBits: Avoid color mapping, or even try faking out color mapping by setting your ctSeed to be the same. Alignment of pixels in the source map relative to their alignment to the destination pixel map can be important. If the source and destination rectangles are different sizes, CopyBits has to scale the copied image, which slows it down a lot. Also dithering and bit depth has effect on the speed of CopyBits.
  4914. Whereas QuickDraw often trades performance for flexibility, there are times we’d just as soon trade flexibility for performance. In these cases, we can achieve tremendous gains in speed by writing custom routines to draw to off-screen worlds. I recommend the article “Drawing in GWorlds for speed and versatility” (develop, issue 10) which shows you exactly how to do that.
  4915. Many developers want to go beyond the speed of QuickDraw. Writing directly to the screen can allow you to create faster animation and graphics than possible with QuickDraw. However, Apple has always maintained that writing to video memory is unsupported, since it may cause your application to break on future systems. If you write directly to the screen, your application will forfeit the use of many Toolbox managers and will put future compatibility at risk. Since most applications require the Window Manager and other basic Macintosh managers, writing to the screen is for only a few specialized applications, such as video games and some animation packages that compete on the quality and speed of graphics. The most important thing to remember is don’t write directly to the screen if you don’t have to. But if you do need to, an article that provides some guidelines is “Graphical Truffles: Writing Directly to the Screen,” develop, Issue 11.
  4916. Following are some additional articles that animation and game developers find useful:
  4917. • “Palette Manager Animation,” develop, Issue 5.
  4918. • “Using the Palette Manager Off-Screen,” develop, Issue 10.
  4919. • “QuickDraw’s CopyBits Procedure: Better Than Ever in System 7.0,” develop, Issue 6.
  4920. • “Graphical Truffles: Animation at a Glance,” develop, Issue 12.
  4921. Also, some sample code that can speed your development is given as SC.015.Offscreen and SC.016.OffSample (Dev CD Jan 93:Technical Documentation:Sample Code: Macintosh Sample Code).
  4922. Animation on the Macintosh does take some work. Nevertheless, we’ve seen some pretty amazing animations developed on the Macintosh.
  4923. Inside Macintosh Volume V PnPixPat & BkPixPat doc fix
  4924. Date written:  12/4/92
  4925. Last reviewed:  3/1/93
  4926. Inside Macintosh Volume V (page 103) says that when a PICT pattern opcode (for instance, 0x0012) comes along, and the pattern isn’t a dither pattern, the full pixMap data follows the old-style 8-byte pattern. The full pixMap data structure described on page 104 indicates that a pixMap starts with an unused long (baseAddr placeholder), followed by the rowBytes, bounds, and so on. However, looking at the Pict.r file on the October 1992 Developer CD, at the same opcode (BkPixPat == 0x0012), the first data field after the old-style pattern (hex string[8]) is the rowBytes field (broken down into three bitstrings). The baseAddr placeholder field isn’t there. Which is correct?
  4927. ___
  4928. The Inside Macintosh documentation on pages V-103 and V-104 is wrong. The Pict.r file correctly describes the format of the PnPixPat and BkPixPat opcodes. So there shouldn’t be a baseAddr field in the pixMap record of a pattern as stored in the PnPixPat of a PICT. However, the baseAddr does occur in a 'ppat' resource as described on page V-79. Thanks for pointing out this discrepancy.
  4929. Disabling Macintosh Color QuickDraw for testing
  4930. Date written:  9/14/92
  4931. Last reviewed:  6/14/93
  4932. Is there an easy way to disable Color QuickDraw on a Macintosh? I want to do this for testing our application, to make sure it works correctly on a machine without Color QuickDraw.
  4933. ___
  4934. There’s no easy, or perhaps even hard way to disable features built into the system software your particular machine requires. It’s designed to work well, not to be toggle-able.
  4935. Even the hard way isn’t a sure thing—trying to patch out all the Color QuickDraw traps could confuse the rest of the system software, which internally may use undocumented routines to accomplish its tasks.
  4936. The easiest way to test on non-Color QuickDraw machines is to get one. Fortunately, the machines without Color QD are the lowest end of the Macintosh price spectrum—such as the Macintosh Classic, PowerBook 100, and Macintosh SE. You can probably rent or borrow one of these if the prices don’t fit your current budget.
  4937. Using a Macintosh PICT file that’s larger than available memory
  4938. Date Written:  6/18/90
  4939. Last reviewed:  6/14/93
  4940. How can I read a 2 MB PICT file into only 1 MB of memory?
  4941. ___
  4942. You can’t read it in since you don’t have enough memory, but drawing the picture contained in the file using a technique called “spooling” increases your chances of using a 2 MB PICT file with 1 MB memory. Spooling is documented in the Color QuickDraw chapter of Inside Macintosh Volume V (pages 88–89).
  4943. Getting a single scan line from a PICT file
  4944. Date Written:  6/18/90
  4945. Last reviewed:  6/14/93
  4946. Is there any way to obtain a particular scan line from a PICT file?
  4947. ___
  4948. A PICT file may contain more than just pixmaps, so getting one scan line out of it is not possible. The file may also contain other elements that overlap, such as rects and arcs. The only way to obtain a single line is to draw it off-screen and then, once the whole image is in memory, you can go and study individual pixels.
  4949. Determining pixel depth from PICT files
  4950. Date Written:  6/20/90
  4951. Last reviewed:  9/17/91
  4952. How do you find out the pixel size of a PICT file on the disk?
  4953. ___
  4954. A picture is by nature independent of depth. For example, you can have a picture containing DrawRects and LineTos and therefore lacking any info regarding depth.
  4955. On the other hand, if the picture you are looking at has pixmap opcodes in it, then each pixmap contains its own pixel size and in this case a picture can have a number of depths associated with it.
  4956. If you want to see the pixel size for each pixmap opcode in a picture, replace all the bottleneck routines and every time the bitsProc is called you can see the pixmap and get the info out. Since the picture is in a file, you can use the spooling technique described in the QuickDraw chapter in Inside Macintosh Volume V. Be ready to deal with multiple, possibly different, pixmaps as well as direct pixmaps if the picture was created under 32-bit QuickDraw.
  4957. ”KnowsPICT,” on the Developer CD Series disc, extracts this kind of information. The System 7.0 Picture Utilities package gets this information too.
  4958. BitMapToRgn for non-Color QuickDraw Macintosh models
  4959. Date Written:  11/9/90
  4960. Last reviewed:  6/14/93
  4961. Is _BitmapToRegion available on any pre-System 7 non-Color QuickDraw configurations such as the Macintosh Classic, Plus, or SE? If not, is source or a library module available so that I don’t have to take the time and compatibility risk of rolling my own?
  4962. ___
  4963. BitMapToRegion works on pre-color Macintosh systems. You can license BitMapToRegion from
  4964.     Software Licensing
  4965.     Apple Computer, Inc.
  4966.     20525 Mariani Ave. MS:38-I
  4967.     Cupertino, CA 95014
  4968.     AppleLink: SW.LICENSE
  4969.     Phone:(408) 974-4667
  4970. Macintosh QuickDraw pixel map stack requirements
  4971. Date Written:  12/3/90
  4972. Last reviewed:  5/21/91
  4973. What are the guidelines for determining how much of an image CopyBits can copy to a Macintosh pixel map at one time, given a particular set of characteristics for the source map and the destination map and given how much stack space is available? For example, say that we have an 8-bit-deep pixmap to be copied to a 32-bit-deep pixMap using the ditherCopy mode and expanded by a factor of 4, and we have 45K of stack space.
  4974. ___
  4975. CopyBits’ stack requirement depends on the width of each scan line (rowBytes). The rule of thumb is that you need at least as much stack as the rowBytes value in your image (which can be huge with 32-Bit QuickDraw), with the following additional modifiers: Add an additional rowBytes for dithering; add an additional rowBytes for any stretching (source rect != dest rect); add an additional rowBytes for any color map changing; add an additional rowBytes for any color aliasing. The stack space you need is roughly five times the rowBytes of your image. In general, you’re better off processing narrower scan lines. Reducing the vertical size will not affect stack requirements. Narrow, tall bands (if you can use them) will reduce the stack requirements.
  4976. Color and non-Color QuickDraw trap dispatch differences
  4977. Date Written:  1/28/91
  4978. Last reviewed:  6/14/93
  4979. Why does a call to RGBForeColor cause a corruption of the stack without resulting in an unimplemented trap error on non-Color QuickDraw Macintosh systems?
  4980. ___
  4981. The trap dispatcher on Color QuickDraw and non-Color QuickDraw machines are different. If you look at page 89 of Inside Macintosh Volume I, you’ll see the toolbox trap word format as it was in the days before Color QuickDraw. Bit 9 was “reserved for future use” and was ignored by the trap dispatcher, and so it was normally set to 0. That means that valid toolbox traps could either look like $A8XX or $A9XX as long as the auto-pop bit was turned off. Color QuickDraw machines have a trap dispatcher that uses that reserved bit to allow for more trap words, and therefore it has a much larger trap dispatch table. Color QuickDraw traps have that reserved bit set, so those traps look like $AAXX or $ABXX.
  4982. When a non-Color QuickDraw machine tests to see if a trap is implemented or not, it just checks the trap dispatch table to see if a routine is implemented for that trap or not. Because the reserved bit is ignored, trap words that look like $AAXX are treated as equivalent to $A8XX and trap words that look like $ABXX are treated as equivalent to $A9XX. The trap word for RGBForeColor is $AA14. If you call RGBForeColor on a non-Color QuickDraw machine, $AA14 is treated as $A814, which is the trap word for SetFractEnable. SetFractEnable is implemented on 128K ROM machines or greater, so no unimplemented trap error occurs.
  4983. If you look at recent DTS sample programs, such as the Utilities sample (SC.025.Utilities, which you can find on AppleLink in Developer Support and on the current developer CD), you’ll see a routine in Utilities.c called TrapExists. It takes into account the size of the trap dispatch table so that you can tell in one call whether a routine is implemented or not regardless of whether it’s a Color QuickDraw trap or not and regardless of what kind of Macintosh you’re running on.
  4984. Under system software version 7.0, the trap dispatcher is modified on non-Color QuickDraw machines so that many Color QuickDraw traps are implemented and work as well as they can in black and white.
  4985. Macintosh OpenCPicture 72-dpi calculation bug
  4986. Date Written:  2/12/91
  4987. Last reviewed:  6/14/93
  4988. The 32-Bit QuickDraw _OpenCPicture call incorrectly calculates the 72-dpi frame width if the height of the native resolution srcRect exceeds 910 dots. To work around this problem, I calculate the 72-dpi frame independently, and store it in the PicHandle returned by _OpenCPicture.
  4989. ___
  4990. It’s a known bug that under Macintosh system software versions 6.0.5 and 6.0.7 with 32-Bit QuickDraw 1.2, OpenCPicture doesn’t properly calculate the right coordinate of the 72-dpi picFrame if the height of the srcRect (native resolution rectangle) multiplied by 72 exceeds $0000FFFF. That works out to a maximum height of 910 pixels, just as you found. This bug is fixed in System 7.0, but gestaltQuickdrawVersion returns $0220 both under system software versions 6.0.5 and 7.0, so you can’t tell whether the bug is fixed that way. Instead, you should use Gestalt with the gestaltSystemVersion selector. If the returned value is $0700 or greater, then let OpenCPicture handle the picFrame calculation; otherwise you should do the calculation yourself.
  4991. GetGWorldPixMap bug and workaround
  4992. Date Written:  3/12/91
  4993. Last reviewed:  6/14/93
  4994. Why does GetGWorldPixMap (when called on a Macintosh II, IIcx, or IIx running system software version 6.0.5 or 6.0.7 with 32-Bit QuickDraw 1.2) return a combination of the device field (two bytes) and the first two bytes of the portPixMap field? Is this a bug?
  4995. ___
  4996. Your analysis of GetGWorldPixMap is exactly right: It doesn’t work correctly in system software version 6.0.5 and 6.0.7 with 32-Bit QuickDraw 1.2. It returns a value that’s two bytes before the value it’s supposed to return.
  4997. The solution is to use GWorldPtr->portPixMap instead of GetGWorldPixMap. It’s safe to do this, but you should use GetGWorldPixMap under System 7. Not only is the bug fixed there, but dereferencing the port is dangerous under System 7 because it may not be CGrafPort. Use Gestalt with the gestaltQuickdrawVersion selector to determine whether you can use GetGWorldPixMap. If Gestalt returns a value from gestalt8BitQD ($0100) through gestalt32BitQD12 ($0220), then GetGWorldPixMap either doesn’t exist or is the buggy version. If it returns gestalt32BitQD13 ($0230) or higher, then GetGWorldPixMap does exist and works correctly. Interestingly, GetGWorldPixMap can be called on a black-and-white QuickDraw machine under System 7. It returns a handle to a structure which should be treated as a BitMap structure, though there are some undocumented fields after the normal BitMap fields. To tell whether GetGWorldPixMap is available on a black-and-white QuickDraw machine, you must check the system software version by calling Gestalt with the gestaltSystemVersion selector. If it returns $0700 or higher, GetGWorldPixMap is available.
  4998. System 7 TextMode problem and workaround
  4999. Date Written:  6/12/91
  5000. Last reviewed:  8/13/91
  5001. Our application uses the TextMode (blend + mask) as documented in Inside Macintosh Volume V (blend is equal to the current ditherCopy constant) to make translucent text. Under System 7, this transfer mode causes garbage to appear when the text is drawn. Is there a way to work around the problem? Will there be a fix?
  5002. ___
  5003. The problem you are seeing is due to the use of CopyDeepMask instead of the old-fashioned CopyBits to do the job. It is being studied now, and the hope is that it will work as advertised in a future release. One workaround is to render the text to an off-screen pixmap and then call CopyBits (using blendMode) to actually put it in the picture.
  5004. Using dithering and animation on the same Macintosh image
  5005. Date Written:  6/19/91
  5006. Last reviewed:  6/14/93
  5007. When setting up a dithered grayscale image for subsequent animation (to adjust brightness, for example), a conflict arises between the use of Palette animation and the ditherCopy CopyBits mode. This problem is demonstrated in the develop #5 GiMeDaPalette code sample: If you change srcCopy to ditherCopy in the CopyBits call, then run the program and select Animate, the resulting image is pure black and white, with what appears to be an attempt to dither with just the black-and-white color table entries (that are not reserved for animation).
  5008. This happens because ditherCopy tries to use the inverse table to do color matching, but when the image is animated, the inverse table colors are limited to just black and white.
  5009. To work around the problem, you can jump into the bottlenecks and when you see the PICT hitting the opcode for CopyBits, change the mode adding the ditherCopy constant. This way the dithering happens when you do the call to DrawPicture and not later on. This makes it possible to use dithering and animation on the same image.
  5010. Rendering color PICTs in a black-and-white environment
  5011. Date Written:  7/22/91
  5012. Last reviewed:  9/17/91
  5013. I want to be able to render a color PICT as a black-and-white image substituting patterns for colors. My images are pretty small and have fewer than 16 colors. What do you suggest as the easiest way?
  5014. ___
  5015. One easy way is to take advantage of 32-Bit QuickDraw and System 7.0’s ditherCopy transfer mode modifier or flag (documented in Inside Macintosh Volume VI, page 17-17). Call DrawPicture into an off-screen pixmap with the pixel depth of the original color PICT. Then call CopyBits to copy the pixmap to the screen, with srcCopy + ditherCopy as the transfer mode. This will result in a nicely dithered image on the black-and-white end.
  5016. Under System 6 without 32-Bit QuickDraw, the solution is not nearly so cut and dried. One way might be to take advantage of the fact that DrawPicture goes through the QuickDraw bottlenecks for drawing. For each grafproc in your PICT, you’d intercept StdBits during DrawPicture and call your own dithering routine to examine the foreground color and set the pen pattern or fill pattern so that it has about the same lightness as the original color.
  5017. Well, this came out as a great sales pitch for writing a System 7-savvy app!
  5018. Highlighting ignored if foreground same as background color
  5019. Date Written:  8/7/91
  5020. Last reviewed:  6/14/93
  5021. Under System 7, but not System 6, HiliteMode doesn’t work when the foreground and background colors are similar. Is this a bug?
  5022. ___
  5023. Yes, it’s a bug. The problem you encounter exists whenever the background and foreground color map to the same color table index. If the foreground color is the same as the background color, highlighting is ignored. Therefore, you should always make sure the foreground and background colors are different when using HiliteMode.
  5024. Gestalt 'qdrw' selector bug and workaround
  5025. Date Written:  8/1/91
  5026. Last reviewed:  6/14/93
  5027. Why does Gestalt tell me I have Color QuickDraw features on a non-Color QuickDraw machine?
  5028. ___
  5029. The gestaltQuickdrawFeatures ('qdrw') selector, used for determining your system’s Color QuickDraw features, has a bug that causes it to tell you incorrectly that noncolor machines have color. The fix is quite simple: Gestalt has another selector, gestaltQuickdrawVersion ('qd  '), which simply returns the QuickDraw version number. This version number is < gestalt8BitQD for classic QuickDraw and >= gestalt8BitQD for Color QuickDraw (see Inside Macintosh Volume VI, page 3-39, for more information). The trick is to ask Gestalt for the QuickDraw version first; once you’ve determined that you have Color QuickDraw, the 'qdrw' selector is OK to use to find out specifics.
  5030. GetPixelsState is slow sometimes
  5031. Date Written:  8/27/91
  5032. Last reviewed:  6/14/93
  5033. Why do I sometimes see incredible slowdowns under System 7.0 when calling either GetPixelsState or LockPixels (I’m not sure which) for the PixMapHandle of a GWorld allocated in temporary memory?
  5034. ___
  5035. GetPixelsState takes an arbitrary amount of time since it makes a call to RecoverHandle to get the handle pointing to the baseaddr. Therefore, the slowdown you see as actually due to the call to RecoverHandle, which is slow because it must traverse the heap to find the pointer to the baseaddr. LockPixels is not responsible for the slowdown because it does not make call to any traps that could take an extended amount of time.
  5036. OpenCPicture and PICTs other than 72 dpi
  5037. Date Written:  10/2/91
  5038. Last reviewed:  6/14/93
  5039. Can I use OpenCPicture to create PICTs with a higher resolution than 72 dots per inch (dpi)?
  5040. __
  5041. There’s good news and bad news: The good news is that you’re on top of the situation, which means the bad news is that there aren’t better ways to do what you want to do, mostly. Here’s the scoop:
  5042. You can use vRes and hRes in pictures opened with OpenCPicture to tell QuickDraw it’s not a 72-dpi picture, and as long as the application that receives the picture uses DrawPicture to image it, QuickDraw will Do The Right Thing—scaling it on the screen to 72 dpi instead of making it humongously large. Unfortunately, this way you lose hairlines; if you print such a picture to a 72-dpi grafPort (like the LaserWriter driver normally returns), you’ll get 1/72-inch lines instead of 1/300-inch lines as you probably want.
  5043. (This can work correctly, but the receiving application has to notice that your picture is bigger than 72 dpi and ask PrGeneral to increase the resolution of the printing grafPort accordingly, and this doesn’t always or often happen.)
  5044. No System 7 QuickDraw alpha channel support
  5045. Date Written:  10/23/91
  5046. Last reviewed:  6/14/93
  5047. How can I directly access the alpha channel (the unused 8 bits in a 32-bit direct pixel using QuickDraw) under System 7? Under System 6 it was easy, but under System 7’s CopyBits the alpha channel works with srcXor but not with srcCopy.
  5048. ___
  5049. With the System 7 QuickDraw rewrite, all “accidental” support for the unused byte was removed, because QuickDraw isn’t supposed to operate on the unused byte of each pixel. QuickDraw has never officially supported use of the extra byte for such purposes as an alpha channel. As stated in Inside Macintosh Volume VI, page 17-5, “8 bits in the pixel are not part of any component. These bits are unused: Color QuickDraw sets them to 0 in any image it creates. If presented with a 32-bit image—for example, in the CopyBits procedure—it passes whatever bits are there.”
  5050. Therefore, you cannot rely on any QuickDraw procedure to preserve the contents of the unused byte, which in your case is the alpha channel. In fact, even CopyBits may alter the byte, if stretching or dithering is involved in the CopyBits, by setting it to 0. Your alternatives are not to use the unused byte for alpha channel storage since the integrity of the data cannot be guaranteed, or not to use QuickDraw drawing routines that can alter the unused byte.
  5051. BitsToRgn and MPW BitMapToRegionGlue
  5052. Date Written:  10/29/91
  5053. Last reviewed:  6/14/93
  5054. Which version of the system software first contained the call BitsToRgn? Is there a workaround for this call if my users have an earlier version of system software?
  5055. ___
  5056. The call BitmapToRegion was introduced with 32-Bit QuickDraw and became fully documented in Volume VI of Inside Macintosh, which is primarily System 7 information. However, since the differences between System 7’s QuickDraw and 32-Bit QuickDraw are minor, most of System 7’s QuickDraw routines are available in system software prior to System 7.0 using the 32-bit QuickDraw INIT.
  5057. To check to see if a system contains 32-bit QuickDraw, you can use the following snippet of code:
  5058.     /* Find out if GWorlds and CQD are implemented on this machine */
  5059.     (void) Gestalt (gestaltQuickdrawVersion, /*<*/&qdVersion);
  5060.     gHasGWorlds = (qdVersion > gestaltOriginalQD && 
  5061.                    qdVersion < gestalt8BitQD)
  5062.                   || qdVersion >= gestalt32BitQD;
  5063. If you are using MPW as a development platform, MPW has a library call you can use that will allow you to use the routine regardless of whether or not 32-bit QuickDraw exists. The glue routine is called BitMapToRegionGlue() and is available to MPW users. Substitute this call for BitMapToRegion calls and the glue code will take care of patching in the proper code if 32-bit QuickDraw does not exist. If you’re using Think C, you can use the oConv utility to convert the MPW object file into a Think C usable format.
  5064. Ensuring even rowBytes for 'cicn' resources
  5065. Date Written:  12/4/91
  5066. Last reviewed:  6/14/93
  5067. Is there any way to force bitmaps and masks within a 'cicn' resource to have an even rowBytes (using ResEdit)? I want to avoid duplicating icon bitmaps—one for color systems set to B&W and one for B&W systems—to reduce program size as well as development and maintenance costs. The bitmaps in the 'cicn' can also be sized specifically to the task, whereas the old B&W icons are of a fixed size and contain no sizing information. It’s simple enough to read in a 'cicn' and extract the bitmap. The problem is that on a 68000 (no Color QuickDraw), if rowBytes is odd, an odd address trap results.
  5068. ___
  5069. There isn’t any way to get ResEdit itself to create bitmaps with even rowBytes for 8 x 8 'cicn' resources, but here are few suggestions:
  5070. You could process your 'cicn' resources first, so that they have bitmaps as you require them. To alter the resource with a quick little program would be trivial, especially given that the bitmap data sits last in the 'cicn'. All you’d need to do is expand the bitmap image data by padding each line to an even length and then changing the rowBytes value. Or you could de-rez the 'cicn's and patch them with a text editor, either by hand or with a search-and-replace script of some kind.
  5071. CopyBits blend mode: OpColor’s affect & eliminating banding
  5072. Date Written:  12/11/91
  5073. Last reviewed:  6/14/93
  5074. I have two gray-colored pixmaps that I wish to blend together; one is on the screen, the other in an off-screen pixmap. I use CopyBits to copy the off-screen to the screen, but it does not seem to blend them. Instead, it seems to match the colors of the screen bitmap to the closest colors in some table, thus having the effect of reducing the number of colors displayed on the screen bitmap. Any suggestions?
  5075. ___
  5076. There are two distinct questions here: 1) Why ain’t it blending? and 2) What’s this banding for? The first problem is almost certainly because OpColor isn’t set properly. This is a third, implicit, operand on several arithmetic graphics operations, including blend. For blend, it describes the proportions to mix the source and destination colors in the blend. For an equal mix, you should set this color to a halfway gray. (Call OpColor() with a color where red, green, and blue all equal $8000.) This effect is described in the description of the blend mode on page 60 of Inside Macintosh Volume V. Unfortunately, the initial value for OpColor is black (0,0,0), so you were seeing no mixing of your off-screen data.
  5077. The second half of your question is why you’re getting a banding effect. (When you fix the above problem, you’ll still get banding.) Unfortunately, the arithmetic modes are constrained by the size of the inverse table. As your screen no doubt uses the default 4-bit inverse table, you’ll find that you’ll get only 2^4 = 16 levels of gray. If you enlarge your screen’s inverse table to 5 bits, the maximum allowable, you’ll still only get 32 gray levels. (To do this, set the gdResPref field in the GDevice to 5, then call MakeITable().) The only way to get a fully-gradual, great-looking effect is to do all the work off-screen in 24-bit deep pixmaps, and then copy it to the screen. Because they can operate directly on colors, rather than having to work through the intermediary of color indices, direct pixmaps are not limited by inverse tables (in fact, they don’t even have real inverse tables). You could use 16-bit pixmaps, but they only provide 32 grays (having only 5 bits for each component), so this wouldn’t be any better than increasing the size of the inverse table.
  5078. Icon dimming under System 7 and System 6
  5079. Date Written:  1/6/92
  5080. Last reviewed:  6/14/93
  5081. When you bring up the Finder windows under System 7 on a color system and click a control panel item icon, it paints itself that fancy gray. How can I get that effect?
  5082. ___
  5083. To get the fancy System 7 icon dimming to work in your program, read the Macintosh Technical Note “Drawing Icons the System 7 Way,” and use the icon-drawing routines contained in it. The routines show how to use the Icon Toolkit, which is what the Finder uses. If you want the same effect under System 6, you’ll have to emulate the dimming of the icons via QuickDraw; the IconDimming sample code in the Snippets folder on the Developer CD Series disc shows how to do this.
  5084. QuickDraw out of memory if debugger invoked by “Jackson”
  5085. Date Written:  3/11/92
  5086. Last reviewed:  6/14/93
  5087. I am getting a strange bug in which the Macintosh debugger is being invoked by an A-trap marked “Jackson” when I call SetCCursor in certain situations and a second monitor is hooked up. The cursor structure being passed appears to be valid. I’ve also been crashing unexpectedly in this same spot for the past few weeks. I assume Jackson is some kind of error assertion that was left in System 7’s Color QuickDraw code. What gives?
  5088. ___
  5089. Jackson was a code name for 32-Bit QuickDraw. The trap you refer to is in fact never called; it’s not supposed to be encountered by you ever. The trap is reserved for Apple to use in future versions of Color QuickDraw. If you examine the code directly preceding the _Debugger, you will notice that it is doing
  5090.         MOVEQ      #$19,D0
  5091.         JSR        ([$1524])
  5092. which for you and me is
  5093.          MoveQ #25,D0                ; say that memory is full…
  5094.         _SysError                    ; and call syserror
  5095. the line following would be...
  5096.         _Debugger ; Hey! sysError came back! Better drop into the debugger
  5097. What’s all this tell you? You have a debugger installed that is rts’ing from the SysError vector (you aren’t supposed to return from SysError normally), or you have installed your own SysError vector which is rts’ing. At any rate, if you examine the code directly following the debugger statement and see what it does, you might imagine the source code looks something like this:
  5098. MemFull       MoveQ #25,D0              ; say that memory is full...
  5099.               _SysError                 ; and call syserror
  5100. ; If it returns better go into the debugger since its not supposed to return
  5101.               _Debugger                 ; Hey! sysError came back!
  5102. ;
  5103. CallNewHand   _NewHandle
  5104.               bne.S  MemFull            ; could not get the memory, just die
  5105.               rts
  5106. What’s happening is that you’re running out of memory somehow (several places call MemFull, not just the above place), so you’d need to use a stack crawl to figure out how you got there. But, the bottom line, QuickDraw has run out of memory and cannot continue; it tried to put up a system error dialog to tell the user and for some reason the machine did not get restarted and the SysError vector returned. You are now in your debugger, since QuickDraw put up the system error dialog because it could not continue.
  5107. ditherCopy not supported on LaserWriter or ImageWriter
  5108. Date Written:  5/31/91
  5109. Last reviewed:  11/6/91
  5110. ditherCopy is not supported on LaserWriters or ImageWriters. On a LaserWriter, ditherCopy gets misinterpreted and inverts the image. On an ImageWriter it’s treated as a srcCopy. The ImageWriter driver doesn’t support color grafPorts, which is the only way to do the pixel image required for ditherCopy. Use srcCopy instead for both printers.
  5111. Macintosh Color QuickDraw CalcCMask and SeedCFill clarified
  5112. Date Written:  1/1/90
  5113. Last reviewed:  11/21/90
  5114. I’m having trouble using CalcCMask and SeedCFill. What am I doing wrong?
  5115. ___
  5116. There is some confusion regarding the use of the Macintosh Color QuickDraw routines CalcCMask and SeedCFill, which are analogous to the older CalcMask and SeedFill. Much of the confusion was caused by early documentation errors. Be sure you have the release version of Volume 5 of Inside Macintosh and version 2.0 or later of the MPW interface files.
  5117. The correct interface for CalcCMask is:
  5118. PROCEDURE CalcCMask(srcBits, dstBits: BitMap;
  5119.           srcRect, dstRect: Rect;
  5120.           seedRGB:     RGBColor;
  5121.           matchProc:    ProcPtr;
  5122.           matchData:    LongInt);
  5123. The correct interface for SeedCFill is:
  5124. PROCEDURE SeedCFill(srcBits, dstBits: BitMap;
  5125.           srcRect, dstRect: Rect;
  5126.           seedH, seedV:   INTEGER;
  5127.           matchProc:    Ptr;
  5128.           matchData:    LongInt);
  5129. Each routine calculates a one-bit deep bitmap representing either the mask or the fill area depending upon the routine. In both cases, the source bitmap may be either a bitmap or a pixmap, but the destination must be a bitmap, because it must have a depth of one-bit.
  5130. It is difficult to pass a pixmap for the source parameter because of Pascal’s type checking. To get around this difficulty, you can declare a new type:
  5131.      BitMapPtr  =  ^BitMap
  5132. then use it to coerce the pixmap as follows:
  5133.      SeedCFill(BitMapPtr(@myPixMap)^, ...);
  5134. If you have a PixMapHandle, do the following:
  5135.      SeedCFill(BitMapPtr(myPixMapHandle^)^, ...);
  5136. If you are using a grafPort (or a window), you can pass myWindow^.portBits and not have to worry about whether the port uses a bitmap or a pixmap.
  5137. Most of the other parameters are explained in detail in Inside Macintosh. To use the matchProc and the matchData parameters, though, you need more information.
  5138. As stated in Inside Macintosh, the matchProc parameter is a pointer to a routine that you would like to use as a custom SearchProc. To better understand how this is used, it is helpful to know how SeedCFill and CalcCMask actually work.
  5139. Both routines start by creating a temporary bitmap which, by definition, is one bit deep. The source pixmap (or bitmap) is then copied to the temporary bitmap using CopyBits. This copy causes the image to be converted to a depth of one-bit. Now with a normal black-and-white image, the standard CalcMask or SeedFill routine is used to generate the destination bitmap.
  5140. Most of the real work is done in the original call to CopyBits, which maps the pixmap image to a monochrome bitmap equivalent. For each color in the source pixmap, CopyBits will map it to either black or white. Which colors map to black and which ones to white is determined by the SearchProc.
  5141. SeedCFill installs a default SearchProc that maps all colors to black except for the color of the pixel at (seedH,seedV). SeedFill then calculates as usual the fill mask for the white bits .
  5142. The default SearchProc for CalcCMask maps all colors to white except the color passed in the seedRGB parameter. The seedRGB parameter, then, would be the color of the item that you wanted to “lasso.”
  5143. But suppose you want to fill over all colors that were shades of green, not just the particular shade of green at (seedH,seedV). Or maybe you want to fill over all colors that are lighter than 50 percent brightness. Or maybe you want to use dark colors as edge colors for CalcCMask. To do such things, you need to pass a pointer to your own SearchProc in the matchProc parameter.
  5144. Because your matchProc is just a custom search procedure for the Color Manager, it should be declared as one, but Volumes I–V of Inside Macintosh have documented this routine incorrectly. The correct declaration for a custom SearchProc is as follows:
  5145. FUNCTION SearchProc(VAR RGB: RGBColor;
  5146.           VAR result: LongInt) : Boolean;
  5147. Normally, as each SearchProc is installed, it is added to the head of the SearchProc chain, so that it is called before all of the other ones that were already installed. When a SearchProc is installed, it can do one of three things:
  5148. 1. Completely ignore the call by returning FALSE and not modifying any of the input parameters;
  5149. 2. Completely handle the call by setting the result parameter to be the index into the color table that matches (according to your rules) the RGB parameter. In that case, the SearchProc returns TRUE;
  5150. 3. Partially handle the call by modifying the RGB parameter, then returning FALSE.
  5151. In cases 1 and 3, the Color Manager continues down the SearchProc chain until it finds one that returns TRUE. If none of the custom routines handle the call, then the built-in default routine is used. In case 3, you can change the RGB color that is being matched. For example, if you want all shades of green to map to pure green, modify the RGB color, then return FALSE, letting the Color Manager find the index of that green in the color table.
  5152. In case 2, you return TRUE to indicate that you handled the call, and you return the color table index in the result parameter. The Color Manager then uses that index. For example, if you want to substitute white for all colors that can’t be matched exactly in the color table, then each time you get called you either return the index into the color table of the exact color, or 0 (which is the index for white) for all other colors.
  5153. A custom SearchProc for SeedCFill and CalcCMask should always return TRUE because the default Color Manager SearchProc usually doesn’t make sense. Because SeedCFill and CalcCMask are using CopyBits to copy to a 1-bit bitmap, you need to set the result to be either 0 or 1 (the only possible values in a 1-bit bitmap). A result of 0 is white, and a result of 1 is black.
  5154. All colors for SeedCFill that should be “filled over” would generate a result of 0 (white), and all colors that stop the fill generate a 1 (black). SeedFill is then called to fill the white area. All colors for CalcCMask that you want to form boundaries should generate results of 1 (black).
  5155. When your SearchProc gets called, the gdRefCon field of the current GDevice (theGDevice^^.gdRefCon) contains a pointer to the following record:
  5156.     matchRec  =  RECORD
  5157.       red:       Integer;
  5158.       green:     Integer;
  5159.       blue:      Integer;
  5160.       matchData: LongInt;
  5161.     END;
  5162. The red, green, and blue parameters for SeedCFill are the values of the color of the pixel at (seedH,seedV). For CalcCMask, they are the fields from the seedRGB parameter. Your SearchProc can use this information to decide which colors are “fill-over” colors and which colors are “boundary” colors. For example, if you always set (seedH,seedV) to be the mouse point, your SearchProc then bases its decisions using the color of the pixel under the cursor. For example, the user clicks a shade of green, so all shades of green get filled over.
  5163. The matchData field contains the value that you passed into the SeedCFill or CalcCMask routines in the matchData parameter. The use of this field is completely user-defined. For example, since your SearchProc routine may be a separate module, you might want to use this field to pass a handle to your variables. This field can contain a handle, a pointer, a long integer, or whatever; or you can just ignore this field altogether.
  5164. Warning: There are some features of CalcCMask and SeedCFill you should be aware of. To understand them, you should be familiar with the use of CalcMask and SeedFill, which are described in the QuickDraw chapter of Inside Macintosh Volume IV.
  5165. CalcCMask and SeedCFill both use a parameter set that is very similar to the one used by CopyBits. CalcMask and SeedFill, however, are a different story. Instead of passing bitmaps and rectangles to SeedFill and CalcMask, these routines use an unusual set of parameters that describe the memory to be operated upon in terms of pointers, height, width, and offsets to the next row (rowBytes). Although these parameters are fairly easy to calculate, there are some limitations.
  5166. The most restrictive limitation is that the width of the rectangle used must be an even multiple of 16 bits. This limitation exists because the width of the rectangle is passed to SeedFill and CalcMask as a number of words (2 bytes). When calculating this parameter, SeedCFill and CalcCMask round down to an even word boundary. This rounding means that the rectangles you pass to CalcCMask and SeedCFill should be an even multiple of 16 pixels in width. If they are not, then the rightmost portion of the mask will be garbage.
  5167. To figure out the color of the pixel at (seedH,seedV), SeedCFill calls GetCPixel. GetCPixel finds the color of the pixel at (h,v) in the current port. Therefore, if you pass a pixmap that is not the pixmap of the current port you will get bizarre results. In other words, seedH and seedV are expressed in the local coordinates of the current port, not the coordinate of the source pixmap.
  5168. You have two methods to make it work. First, always pass the pixmap of the current port as the source parameter. If you are using an off-screen pixmap, it is a good idea to have an associated port for it, and then call SetPort, passing it a pointer your off-screen port, before you call SeedCFill.
  5169. The second method involves letting SeedCFill get some wrong value for the color at (seedH,seedV) then using your own custom SearchProc to do the real work. The default SearchProc for SeedCFill relies on getting the correct color, but your SearchProc doesn’t have to.
  5170. SeedCFill also makes the assumption that the seedH and seedV parameters are in the local coordinate system of the destination bitmap. This assumption comes into play when SeedCFill calculates the seedH and seedV parameters for SeedFill.
  5171. All this means that SeedCFill only works correctly if the source pixmap, destination pixmap, and current port all use the same coordinate system. Because of the above problem, this is almost automatic since the current port’s portRect and the bounds of the source pixmap have to be the same anyway.
  5172. The easiest way to make all this work is to have your main port be an even multiple of 16 pixels wide. Then, make sure that your source and destination structures (pixmap or bitmap) are all the same size and all have origins of (0,0).
  5173. Macintosh PICT color picture file format
  5174. Date Written:  1/1/90
  5175. Last reviewed:  6/14/93
  5176. Is there a general file format for color pictures that is common to all of the color paint programs? If so, where is it documented?
  5177. ___
  5178. Apple supports (and encourages developers to support) one file type for pictures: the PICT file type. Most paint-type programs handle PICT files.
  5179. A PICT file is composed of two parts in its data fork; the first 512 bytes are for the file header, which contains application-dependent information. You have to contact the individual publishers to find out their particular data structures. For example, you can contact Claris Technical Support at AppleLink CLARIS.TECH or (415) 962-0371 for the file header MacDraw writes to its files.
  5180. The rest of the data in the file is picture data as created by Macintosh QuickDraw with OpenPicture. You can find the information about this data in Volume V of Inside Macintosh (pages 84–105); this section also shows how to read/write PICT files.
  5181. You can also check the Macintosh Tech Note “Displaying Large PICT Files” for more details on the subject.
  5182. X-Refs:
  5183. DTS Macintosh Technical Note “QuickDraw’s Internal Picture Definition”
  5184. DTS Macintosh Technical Note “Displaying Large PICT Files”
  5185. Mac pixmap is clipped to visRgn defined by screenBits.bounds
  5186. Date Written:  1/1/90
  5187. Last reviewed:  11/21/90
  5188. I’m drawing into a large off-screen bitmap (pixmap), but anything drawn outside the 640- by 480-pixel Macintosh screen area doesn’t get written to the pixmap. Why not?
  5189. ___
  5190. When you create a new port with OpenPort or OpenCPort the visRgn is initialized to the rectangular region defined by screenBits.bounds (IM I:163). If your port has a large portRect, any drawing will be clipped to the visRgn and you will lose any drawing outside of the screenBits.bounds rectangle.
  5191. To correct this set the visRgn of the port to coincide with your port’s portRect after creating the port.
  5192. Also note that OpenPort initializes the clipRgn to a wide-open rectangular region (-32768, -32768, 32767, 32767). Some operations, like OpenPicture, can fail with this setup, so try setting clipRgn to a smaller rectangle.
  5193. X-Refs:
  5194. DTS Macintosh Technical Note “Pictures and Clip Regions”
  5195. DTS Macintosh Technical Note “Drawing into an Off-Screen Pixel Map”
  5196. Using Macintosh System 7 OpenCPicture for higher resolution
  5197. Date Written:  1/1/90
  5198. Last reviewed:  6/14/93
  5199. We want to use OpenCPicture for higher resolution, not for color per se. Can OpenCPicture in System 7 be used with non-Color as well as Color QuickDraw Macintosh computers?
  5200. ___
  5201. Yes, with System 7, OpenCPicture can be used to create extended PICT2 files from all Macintosh computers. Under System 6.0.7 or later, you must test for 32-Bit QuickDraw before using OpenCPicture. You can do this by calling Gestalt with the gestaltQuickdrawVersion selector. If it returns gestalt32BitQD or greater, then 32-Bit QuickDraw is installed.
  5202. How to identify 32-Bit QuickDraw version
  5203. Date Written:  1/1/90
  5204. Last reviewed:  6/14/93
  5205. How can my program find out which version of Macintosh 32-Bit QuickDraw is running?
  5206. ___
  5207. The following code snippet demonstrates how to use the Gestalt Manager to determine which version of 32-Bit QuickDraw is installed. There is no way to determine the version of 32-Bit QuickDraw before Gestalt. For 32-Bit QuickDraw version 1.2, Gestalt returns 2.2. Inside Macintosh Volume VI describes the Gestalt Manager in detail.
  5208. #defineTRUE0xFF
  5209. #defineFALSE0
  5210. #define Gestalttest0xA1AD
  5211. #define NoTrap0xA89F
  5212. main()
  5213. {
  5214. OSErrerr;
  5215. longfeature;
  5216. if ((GetTrapAddress(Gestalttest) != GetTrapAddress(NoTrap))) {
  5217. err = Gestalt(gestaltQuickdrawVersion, &feature);
  5218. if (!err) {
  5219. if ((feature & 0x0f00) == 0x0000)
  5220. printf ("We have Original QuickDraw version 0.%x\n", (feature & 0x00ff));
  5221. else if ((feature & 0x0f00) == 0x0100)
  5222. printf ("We have 8 Bit QuickDraw version 1.%x\n", (feature & 0x00ff));
  5223. else if ((feature & 0x0f00) == 0x0200)
  5224. printf ("We have 32 Bit QuickDraw version 2.%x\n", (feature & 0x00ff));
  5225. else
  5226. printf ("We don't have QD\n");
  5227. }
  5228. else
  5229. printf ("Gestalt err = %i\n",err);
  5230. }
  5231. else
  5232. printf ("No Gestalt\n");
  5233. }
  5234. Macintosh QDError function under System 6 and System 7
  5235. Date Written:  1/1/90
  5236. Last reviewed:  12/7/90
  5237. Under what System 7 and System 6 conditions is it legal to call the Macintosh QDError function?
  5238. ___
  5239. Under System 7, QDError can be called from all Macintosh computers. (System 7 supports RGBForeColor, RGBBackColor, GetForeColor, and GetBackColor for all Macintosh computers as well.) On a non-Color QuickDraw Macintosh, QDError always returns a “no error.” Under System 6, QDError cannot be used for non-Color QuickDraw Macintosh systems.
  5240. Macintosh CopyBits transfer modes changed for System 7
  5241. Date Written:  1/1/90
  5242. Last reviewed:  6/14/93
  5243. Why do some Macintosh CopyBits transfer modes produce different results for System 7 than for System 6?
  5244. ___
  5245. Under System 6, the srcOr, srcXor, srcBic, notSrcCopy, notSrcOr, notSrcXor, and notSrcBic transfer modes do not produce the same effect for a 16- or 32-bit (direct) pixel map as for an 8-bit or shallower (indexed) pixel map. With Color QuickDraw these classic transfer modes on direct pixel maps aren’t color-based; they’re pixel-value-based. Color QuickDraw performs logical operations corresponding to the transfer mode on the source and destination pixel values to get the resulting pixel value.
  5246. For example, say that a multicolored source is being copied onto a black-and-white destination using the srcOr transfer mode, and both the source and destination are 8 bits per pixel. Except in unusual cases, the pixel value for black on an indexed pixel map has all its bits set, so an 8-bit black pixel has a pixel value of $FF. Similarly, the pixel value for white has all its bits clear, so an 8-bit white pixel has a pixel value of $00. CopyBits takes each pixel value of the source and performs a logical OR with the corresponding pixel value of the destination. Using OR to combine any value with 0 results in the original value, so using OR to combine any pixel value with the pixel value for white results in the original pixel value. Using OR to combine any value with 1 results in 1, so using OR to combine any pixel value with the pixel value for black results in the pixel value for black. The resulting image shows the original image in all areas where the destination image was white and shows black in all areas where the destination image was black.
  5247. Take the same example, but this time make the source and destination 32 bits per pixel. The direct-color pixel value for black is $00000000 and the direct-color pixel value for white is $00FFFFFF. CopyBits still performs a logical OR on the source and destination pixel values, but notice what happens in this case. Using OR to combine any source pixel value with the pixel value for white results in white, and using OR to combine any source pixel value with the pixel value for black results in the original color. The resulting image shows the original image in all areas where the destination image was black and shows white in all areas where the destination image was white—roughly the opposite of what you see on an indexed pixel map.
  5248. The newer transfer modes addOver, addPin, subOver, subPin, adMax, and adMin work consistently at all pixel depths, and often, though not always, correspond to the theoretical effect of the old transfer modes. For example, the adMin mode works similarly to the srcOr mode on both direct and indexed pixel maps. Also, 1-bit deep source pixel maps work consistently and predictably regardless of the pixel depth of the destination even with the old transfer modes.
  5249. Under system software version 7.0, the old transfer modes now perform by calculating with colors rather than pixel values. You’ll find that transfer modes like srcOr and srcBic work much more consistently even on direct pixel maps.
  5250. Which QuickDraw versions support SetEntries
  5251. Date Written:  3/3/92
  5252. Last reviewed:  6/14/93
  5253. I’m calling SetEntries to update the on-screen CLUT. Who implements this call? Does 32-Bit QuickDraw? In other words, does the 32-Bit QuickDraw INIT need to be around for this to work? What about monochrome machines? 
  5254. I’m creating off-screen buffers by hand instead of using GWorlds. Is this the proper way of doing off-screen buffering when we don’t want to require the user to have 32-Bit QuickDraw?
  5255. ___
  5256. SetEntries is part of the Color Manager, which exists with all Color QuickDraw versions. A good rule of thumb to follow is that if it is documented in Inside Macintosh Volume V, you don’t need 32-Bit QuickDraw to use it. Inside Macintosh Volume V documents standard Color QuickDraw. SetEntries does not work on monochrome Macintosh models, including the Classic II, SE, and PowerBooks.
  5257. Off-screen buffering: You should always use GWorlds if they exist; use Gestalt to test for them. This will assure that you can take advantage of the latest speed improvements. It is important to remember that under System 7 NewGWorld and accompanying calls are present in all Macintosh computers including black-and-white systems such as Classic and PowerBook 100 systems.
  5258. Macintosh pixel map maximum rowBytes change
  5259. Date Written:  4/22/91
  5260. Last reviewed:  6/14/93
  5261. The Color QuickDraw section of Inside Macintosh Volume VI states that the restriction on the rowBytes field in a pixmap has been relaxed from $2000 to $4000. When did this happen? Is it true for all 32-Bit QuickDraw versions? This affects our user configuration recommendations.
  5262. ___
  5263. The maximum rowBytes extension to $3FFE or less applies only to 32-bit QuickDraw. Using pixmaps with rowBytes greater than $1FFE when 32-bit QuickDraw is not present is likely to cause problems such as garbage images or system crashes. Remember that 32-bit QuickDraw is always present under System 7.0 or higher.
  5264. Use assembly to flip a 24-bit off-port color pixmap
  5265. Date Written:  5/7/91
  5266. Last reviewed:  7/25/91
  5267. What’s the best approach to horizontally flip a 24-bit off-port color pixmap?
  5268. ___
  5269. Unfortunately, you won’t be able to use CopyBits for this kind of procedure; you’ll have to write your own routine to move each pixel. I’d suggest doing this in assembly language to squeeze the best possible performance out of your code.
  5270. Why PlotCIcon requires GetCIcon instead of Get1Resource
  5271. Date Written:  4/26/91
  5272. Last reviewed:  6/17/91
  5273. Why do I have to use GetCIcon(resID) instead of Get1Resource('cicn',resID) forPlotCIcon to work correctly?
  5274. ___
  5275. You apparently thought something that, at first, I thought also: that GetCIcon(resID) is just a utility routine that translates to Get1Resource('cicn',resID). However, this is not the case; GetCIcon not only gets the 'cicn' resource, but it also performs some minor surgery on the results, fills in some placeholder fields in the resource data, and the like. Basically, PlotCIcon can’t work without the things that GetCIcon does.
  5276. How Macintosh system draws small color icons
  5277. Date Written:  3/31/92
  5278. Last reviewed:  6/14/93
  5279. The code I added to my application’s MDEF to plot a small icon in color works except when I hold the cursor over an item with color. The color of the small icon is wrong because it’s just doing an InvertRect. When I drag over the Apple menu, the menu inverts behind the icon but the icon is untouched. Is this done by brute force, redrawing the small icon after every InvertRect?
  5280. ___
  5281. The Macintosh system draws color icons, such as the Apple icon in the menu bar, every time the title has to be inverted. First InvertRect is called to invert the menu title, and then PlotIconID is called to draw the icon in its place. The advantage of using PlotIconID is that you don’t have to worry about the depth and size of the icon being used. The system picks the best match from the family whose ID is being passed, taking into consideration the target rectangle and the depth of the device(s) that will contain the icon’s image.
  5282. The Icon Utilities call PlotIconID is documented in the Macintosh Technical Note “Drawing Icons the System 7 Way”; see this Note for details on using the Icon Utilities calls.
  5283. Spooling and preserving Macintosh QuickDraw pixmap depth
  5284. Date Written:  2/11/92
  5285. Last reviewed:  6/14/93
  5286. When a picture that contains a pixmap is spooled into a window, how and when is the depth of the pixmap in the picture converted to the depth of the screens the window is on?
  5287. ___
  5288. When a picture is spooled in, if QuickDraw encounters any bitmap opcode, it allocates a pixmap of the same depth as the data associated with the bitmap opcode, expands the data into the temporary pixmap, and then calls StdBits. StdBits is what triggers the depth and color conversions as demanded by the color environment (depth, color table, B&W settings) of the devices the target port may span (as when a window crosses two or more screens).
  5289. If there’s not enough memory in the application heap or in the temporary memory pool, QuickDraw bands the image down to one scan line and calls StdBits for each of these bands. Note that if you’re providing your own bitsProc, QuickDraw will call it instead of StdBits.
  5290. This process is the same when the picture is in memory, with the obvious exception that all the picture data is present; the color mapping occurs when StdBits does its stuff.
  5291. Determining the resolution of a PICT
  5292. Date Written:  6/10/92
  5293. Last reviewed:  6/14/93
  5294. In a version 2 picture, the picFrame is the rectangular bounding box of the picture, at 72 dpi. I would like to determine the bounding rectangle at the stored resolution or the resolution itself. Is there a way to do this without reading the raw data of the PICT resource itself?
  5295. ___
  5296. With regular version 2 PICTs (or any pictures), figuring out the real resolution of the PICT is pretty tough. Applications use different techniques to save the information. But if you make a picture with OpenCPicture, the resolution information is stored in the headerOp data, and you can get at this by searching for the headerOp opcode in the picture data (it’s always the second opcode in the picture data, but you still have to search for it in case there are any zero opcodes before it). Or you can use the Picture Utilities Package to extract this information.
  5297. With older picture formats, the resolution and original bounds information is sometimes not as obvious or easily derived. In fact, in some applications, the PICT’s resolution and original bounds aren’t stored in the header, but rather in the pixel map structure(s) contained within the PICT.
  5298. To examine these pixmaps, you’ll first need to install your own bitsProc, and then manually check the bounds, hRes, and vRes fields of any pixmap being passed. In most cases the hRes and vRes fields will be set to the Fixed value 0x00480000 (72 dpi); however, some applications will set these fields to the PICT’s actual resolution, as shown in the code below.
  5299. Rect      gPictBounds;
  5300. Fixed      gPictHRes, gPictVRes;
  5301. pascal void ColorBitsProc (srcBits, srcRect, dstRect, mode,
  5302.   maskRgn)
  5303. BitMap    *srcBits;
  5304. Rect      *srcRect, *dstRect;
  5305. short      mode;
  5306. RgnHandle  maskRgn;
  5307. {
  5308.   PixMapPtr  pm;
  5309.   pm = (PixMapPtr)srcBits;
  5310.   gPictBounds = (*pm).bounds;
  5311.   gPictHRes = (*pm).hRes;    /* Fixed value */
  5312.   gPictVRes = (*pm).vRes;    /* Fixed value */
  5313. }
  5314. void FindPictInfo(picture)
  5315. PicHandle  picture;
  5316. {
  5317.   CQDProcs    bottlenecks;
  5318.   SetStdCProcs (&bottlenecks);
  5319.   bottlenecks.bitsProc = (Ptr)ColorBitsProc;
  5320.   (*(qd.thePort)).grafProcs = (QDProcs *)&bottlenecks;
  5321.   DrawPicture (picture, &((**picture).picFrame));
  5322.   (*(qd.thePort)).grafProcs = 0L;
  5323. }
  5324. QD 520 - ColorSync Q&As
  5325. QuickDraw    
  5326. Revised by:    Developer Support Center    September 1993
  5327. Written by:    Developer Support Center    June 1993
  5328. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  5329. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  5330. New Q&As in this Technical Note:
  5331. CWNewColorWorld CWord parameter
  5332. CMProfileResponse data structure
  5333. CWNewColorWorld CWorld parameter
  5334. Date Written:   2/22/93
  5335. Date reviewed: 7/2/93
  5336. Can I assume that the value of the ColorSync CWorld parameter returned by the CWNewColorWorld routine isn’t null if the routine was successful? I’d like to determine whether a color world exists by checking the variable for null.
  5337. ___
  5338. You can assume that if no error is returned by CWNewColorWorld, the CWorld parameter will be a valid handle. In other words, it won’t be null if no error is returned.
  5339. CMProfileResponse data structure
  5340. Date Written:   3/18/93
  5341. Last reviewed: 6/24/93
  5342. How do I access fields within the CMProfile data structure?
  5343. ___
  5344. Use the structures defined in the CMApplication.h file. These structures will allow you to directly access all fields up to the profileName. You can’t access the profileName directly because the CMProfileResponse record is variable size. You can determine the profileName by using the GetProfileName call. Likewise, the customData must also be accessed in this way by using the GetProfileAdditionalDataOffset call.
  5345. ColorSync documentation
  5346. Date Written:  2/8/93
  5347. Last reviewed:  4/1/92
  5348. Do you have any documentation that describes ColorSync in more detailed than “The ColorSync Utilities” on the Developer CD? I want to develop a ColorSync-aware printer driver and application.
  5349. ___
  5350. The “ColorSync Utilities” document on the Developer CD is a preliminary draft. Apple is updating it to include more sample code and descriptive explanations. The final document will be included as a chapter in Apple’s forthcoming Inside Macintosh: QuickDraw reference, which will be available later this year.
  5351. “ColorSync: A Tuning Fork for Color,” in the February issue of Apple Direct, provides a ColorSync overview. Also, the Print Hints column in the June 1993 issue of develop, “ColorSync and Printing,” addresses ColorSync implementation issues for products such as yours.
  5352. How Apple Color Printer uses ColorSync
  5353. Date Written:  2/8/93
  5354. Last reviewed:  6/14/93
  5355. What’s the mechanism the Apple Color Printer driver uses for ColorSync?
  5356. ___
  5357. The Apple Color Printer uses the low-level ColorSync color-matching calls to perform color matching in the print bottleneck routines. Thus, color matching happens before rendering so that rendering always occurs with matched colors. For more information, see the section called “What does a printer driver have to do?” in the Print Hints column of the June 1993 issue of develop.
  5358. ColorSync 1.0.2 fixes kNumColorsToMatch bug
  5359. Date Written:  1/20/93
  5360. Last reviewed:  6/14/93
  5361. I tried calling CMMatchColors with different numbers of colors to match; 10,000 worked fine, but 50,000 or greater crashed with a bus error. Is this a bug?
  5362. ___
  5363. This is a bug in ColorSync 1.0 and 1.0.1. The “for” loop inside the Apple CMM uses a short rather than a long. It’s been fixed for version 1.0.2.
  5364. ColorSync responders
  5365. Date Written:  1/18/93
  5366. Last reviewed:  6/14/93
  5367. Which ColorSync responders can I rely on? The ColorSync cdev as I understand it yields the system responder. I don’t have anything else (for example, Color Printer driver); how do I get a monitor and printer responder?
  5368. ___
  5369. The ColorSync documentation doesn’t discuss responders very well. A system profile responder is always available if ColorSync is installed. It can be used only to set the current system profile and to get the current system profile. A printer profile isn’t registered normally and has to be registered by the printer driver when requested to do so with a PrGeneral call.
  5370. For more information, please read “Syncing up with ColorSync” in issue 14 of develop.
  5371. MatchColors and profile handles for CMYK or RGB conversion
  5372. Date Written:  1/18/93
  5373. Last reviewed:  6/14/93
  5374. How do I get the right ProfileHandles to convert CMYK to RGB data and vice versa via the low-level MatchColors call? All routines now are returning “Responder errors” (-180 and -182), a description that doesn’t help much at the moment.
  5375. ___
  5376. To convert CMYK to RGB, you need to have a proper source profile specifying that the data is in CMYK format (dataType = "CMYK"), and a proper destination profile specifying that the data is in RGB format (dataType = "RGB "). You can use ProfileMaker to modify a current profile (that is, 13" RGB) to create the CMYK format; or, you can also use the current system profile obtained by calling GetProfile.
  5377. QD 525 - LaserWriter Utility Q&As
  5378. QuickDraw    
  5379. Revised by:    Developer Support Center    September 1993
  5380. Written by:    Developer Support Center    October 1990
  5381. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  5382. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  5383. SCSI drive format for LaserWriter II NTX with Rev. 3 ROMs
  5384. Date Written:  5/3/91
  5385. Last reviewed:  6/26/91
  5386. What could be causing intermittent PostScript errors from a LaserWriter II NTX with an SCSI hard disk mounted after installing the Rev 3 ROM upgrade?
  5387. ___
  5388. The LaserWriter II NTX with Rev 3 ROMs does not work properly with a hard disk formatted with the LaserWriter Font Utility 1.x. You need to reformat the disk and copy the fonts back onto the hard disk using the LaserWriter Font Utility 2.0.2. Unfortunately, there is no way to make this procedure easier.
  5389. LaserWriter Font Utility copies Postscript file to printer
  5390. Date Written:  9/23/91
  5391. Last reviewed:  10/8/91
  5392. Is there a utility that will send a PostScript file from disk to the LaserWriter?
  5393. ___
  5394. The LaserWriter Font Utility handles this job and is part of the System 7 disk set. On the System 7 Golden Master CD, the path is System 7.0: System Software 7.0: Installer Version: Tidbits folder.
  5395. QD 530 - Palette Manager Q&As
  5396. QuickDraw    
  5397. Revised by:    Developer Support Center    September 1993
  5398. Written by:    Developer Support Center    October 1990
  5399. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  5400. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  5401. New Q&As in this Technical Note:
  5402. GetNewPalette and default palette documentation update
  5403. GetNewPalette and default palette documentation update
  5404. Date Written:   3/10/93
  5405. Last reviewed: 6/24/93
  5406. Our application has a 'pltt' resource containing colors, which is replaced by the user’s palette from a Preferences file if it exists. Sometimes our Color dialog box displays black-and-white or incorrect colors. Does the Palette Manager documentation describe default palettes correctly? Should I call GetNewPalette(0) on my application resource fork instead of calling GetPalette(-1)?
  5407. ___
  5408. The actual implementation of the Palette Manager is somewhat different than documented in Inside Macintosh Volume VI.
  5409. The Palette Manager has two levels of default palettes. First, there’s a system palette that’s loaded at system startup time. This system palette ('pltt', ID#0) is loaded from the system file if it exists and stored in the system heap along with other Palette Manager globals. Once the system is booted, this system palette doesn’t change. Even if you replace the palette in the system file, the new palette isn’t reloaded. If there’s no system palette resource in the system file, the Palette Manager hard codes a 2 entry (black and white) palette as the system palette. The default system file for both Systems 6.0.8 and 7.1 doesn’t have a ('pltt', ID#0) resource. Therefore, it seems that the default system palette is typically an entry palette with black and white.
  5410. The other level of default palette is the application palette. This palette is stored in a low-memory global called AppPalette. You probably won’t find it in any documentation, but the address is $DCC. (This low-memory global is switched during context switches so you don’t have to worry about losing the low-memory global when switching applications.) The Palette Manager loads this default application palette when InitPalette is called. Normally, you don’t call InitPalette directly in your code. Instead, InitWindows calls InitPalette for you. Inside InitPalette, a call to Get1Resource is made with ('pltt', ID#0). Get1Resource differs from GetResource because Get1Resource checks only the first resource file. Since your application is assumed to be at the top of the resource chain, this call will get a palette of ID #0 if it’s available in that file *only*. This actually causes a problem when running an application from a development environment such as Think C.
  5411. Unlike the default system palette, the default application palette can be modified by a call to SetPalette(WindowPtr(-1), newDefaultAppPalette, TRUE). You can also get the default palette with a call to GetPalette(WindowPtr(-1)). When there’s no application default palette, GetPalette(WindowPtr(-1)) uses the default system palette instead. As mentioned earlier, this is typically a 2 entry palette with black and white.
  5412. Lastly, the documentation for the call GetNewPalette on page 20-19 of Inside Macintosh Volume VI is completely misleading. GetNewPalette simply loads in the specified 'pltt' resource using GetResource and then detaches it with DetachResource to make it a handle. It doesn’t attach it to the current window. And, it doesn’t load the default application handle if the specified resource can’t be found.
  5413. SetPalette cUpdates, NSetPalette, and window update events
  5414. Date Written:  9/26/91
  5415. Last reviewed:  6/14/93
  5416. When I pass FALSE in the cUpdates parameter to SetPalette, I still get update events to that window when I modify its palette. What’s going on?
  5417. ___
  5418. SetPalette’s cUpdates parameter controls whether color-table changes cause that window to get update events only if that window is not the frontmost window. If that window is the frontmost window, any changes to its palette cause it to get an update event regardless of what the cUpdates parameter is. When you call SetEntryColor and then ActivatePalette for your frontmost window, the window gets an update event because it’s the frontmost window even though you passed FALSE in the cUpdates parameter. Another important point is that windows that don’t have palettes always get update events when another window’s palette is activated.
  5419. Fortunately, system software version 6.0.2 introduced the NSetPalette routine, which is documented in the Macintosh Technical Note “Palette Manager Changes in System 6.0.2” and on page 20-20 in the Palette Manager chapter of Inside Macintosh Volume VI. This variation of SetPalette gives you the following options in controlling whether your window gets an update event:
  5420. •    If you pass pmAllUpdates in the nCUpdates parameter, your window gets an update event when either it or another window’s palette is activated.
  5421. •    If you pass pmFgUpdates, your window gets an update event when a palette is activated only if it’s the frontmost window (in effect, it gets an update event only if its own palette is activated).
  5422. •    If you pass pmBkUpdates, your window gets an update event when a palette is activated only if it’s not the frontmost window (in effect, it gets an update event only if another window’s palette is activated).
  5423. •    If you pass pmNoUpdates, your window never gets an update event from any window’s palette being activated, including that window itself.
  5424. Restoring Finder desktop colors after using Palette Manager
  5425. Date Written:  8/28/91
  5426. Last reviewed:  8/1/92
  5427. After using the Macintosh Palette Manager, how do I restore the Finder’s desktop colors?
  5428. ___
  5429. The Finder desktop’s colors are restored automatically on quitting applications that use the Palette Manager. Colors aren’t restored automatically when switching from your application to another, but if that application needs a certain set of colors and uses the Palette Manager to get them, then it’ll have them the moment it comes to the front. If you’re concerned about applications that don’t use the Palette Manager, you can use RestoreDeviceClut(gd:GDHandle), passing the handle to the GDevice of the screen you want to reset, or nil if you want to reset all of your devices. Passing nil to RestoreDeviceClut is your best bet, as it is very straightforward, and resets all of your monitors. You may not wish to do this, however, because RestoreDeviceClut is only available on machines with 32-bit color QuickDraw.
  5430. To reset a screen’s GDevice for machines without 32-bit color QuickDraw, you will need to keep track of the color table.When your application starts up, get the GDevice’s color table and save it—you’ll need it later. This value can be found at (**(**GDHandle).gdPMap).pmTable, where gdPMap is a PixMapHandle, and pmTable is a CTabHandle which tells you the absolute colors for this image. These data structures are found in Inside Macintosh Volume V, pages 52 and 119.
  5431. Build your application’s “world” using the Palette Manager, and avoid low-level methods of changing colors. When your application is about to quit and you want to restore the environment to its original state, get the color table you saved in the beginning. Convert this to a palette using CTab2Palette. Then set your window to this palette with SetPalette. This will cause the environment to update to the original color table that you initially got from the GDevice. If the application that is behind your application is Palette Manager friendly, then it will restore the environment to its palette. You may also want to do this procedure at the suspend event, as shown in the DTS sample MacApp program, FracApp. One of the problems that you won’t be able to solve this way involves multiple monitors. You won’t know which one to update. Only the monitor that has the window that you’ve called ActivatePalette on will update.
  5432. If your application changes the color environment with the Palette Manager, then RestoreDeviceClut is called automatically when your application quits. This means that you shouldn’t have to worry about restoring the palette if you don’t want to. There is a catch, however (there always is). When you use the SADE version of MultiFinder (6.1b9), it prevents this from automatically happening. Other versions of MultiFinder don’t have this side effect.
  5433. RestoreDeviceClut and color flash when application quits
  5434. Date Written:  8/23/91
  5435. Last reviewed:  6/14/93
  5436. When my application, which uses a color palette, quits, there is momentary but distracting flash of weird colors in the Finder windows and the desktop temporarily appears in a weird color. Is there any way to get around this?
  5437. ___
  5438. When you quit, RestoreDeviceClut is called to restore the color table and an update event is called to redraw the screen. It’s the delay between the change in the color table and the update event that causes the flash of incorrect colors to be displayed. This, unfortunately, is unavoidable.
  5439. Macintosh Palette Manager and offscreen graphics
  5440. Date Written:  7/22/91
  5441. Last reviewed:  8/1/92
  5442. The Macintosh Palette Manager doesn’t work on offscreen environments the way you’d expect. Unlike color windows, SetPalette will not change the offscreen’s color table; rather it just allows you to use PMForeColor and PMBackColor to set the current drawing color in that environment. To change the offscreen’s color table you’ll need to convert the palette to a color table and then set the resulting color table to the off screen. Calling Palette2CTab will do the converting for you.
  5443. To get around having to use palettes to define the current drawing color in the off screen, you can always use Index2Color and then RGBForeColor to get the color to be set for drawing. A remake of GiMeDaPalette code sample, available on the latest Developer CD Series disc, does offscreen drawing in place of having to continually copy a PICT.
  5444. QD 535 - Picture Utility Q&As
  5445. QuickDraw    
  5446. Revised by:    Developer Support Center    September 1993
  5447. Written by:    Developer Support Center    October 1990
  5448. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  5449. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  5450. GetPictInfo and QuickTime compressed PICT files
  5451. Date Written:  2/24/92
  5452. Last reviewed:  8/1/92
  5453. Is it my imagination, or does GetPictInfo return a bit depth of 1 on QuickTime compressed PICT files?
  5454. ___
  5455. Yep! This is what’s happening: The Picture Utilities Package doesn’t know of the QuickTime Compressed Pixmap opcode (0x8200), so it just skips over the opcode’s data; then it finds the PacksBitRect opcode containing the black-and-white pseudo-alert that you get when you draw the picture on a machine that doesn’t have QuickTime installed, and GetPictInfo reports back this alert.
  5456. Trivia: When QuickTime is installed, it displays the compressed image and then ignores the following PacksBitRect since QuickTime knows it’s only the black-and-white alert.
  5457. NewPalette doesn’t use CTab2Palette to create a palette
  5458. Date Written:  3/12/92
  5459. Last reviewed:  6/14/93
  5460. I’m using the Picture Utilities Package to extract the color table from a picture. After getting the color table, I use NewPalette to construct a palette from the color table (usage = tolerant, tolerance = 0). After I do this, the RGB values in the palette don’t always exactly match the RGB values in the source color table, causing my program to fail. If I use NewPalette without a source color table, and then use CTab2Palette to copy the colors over (again with usage = tolerant, tolerance = 0), the colors match exactly.
  5461. ___
  5462. It turns out that NewPalette doesn’t use CTab2Palette, but copies the RGB fields in a strange way that’s causing the problems you’re seeing. NewPalette copies the high byte in each color table RGB entry into both the high byte and the low byte of the corresponding palette entry. Thus, if the color table entry for red was $F000, it becomes $F0F0. This of course makes no difference to QuickDraw since the low byte isn’t displayed, but if your program expects the low byte to match, that’s where your problem exists. CTab2Palette is different, in that it doesn’t copy the high byte into the low byte unless the pmAnimated bit is set.
  5463. The best solution for your code isn’t to compare the entire RGB value when comparing colors, but rather to compare the high byte of each RGB component separately. If this isn’t possible, the next best solution is for you to use the workaround that you’ve already discovered with CTab2Palette.
  5464. It’s unlikely that the Palette Manager is going to change in the future for something like this. In fact, we would almost call it a “feature” since other developers may even depend on it.
  5465. Spooling PixMaps to disk
  5466. Date Written:  6/10/91
  5467. Last reviewed:  10/22/91
  5468. Do you have sample code for spooling PixMaps to disk in PICT format? Should I write the PICT opcodes to the file myself?
  5469. ___
  5470. Apple recommends that you do not try to write the PICT opcodes yourself. Instead, replace the PutPicProc bottleneck proc, as shown in the Color QuickDraw chapter of Inside Macintosh Volume V on page V-89.
  5471. Two additional samples can be found in the sample code contained in the Developer CDs. Look for: “Tools & Apps: Graphics and Imaging: PICT Stuff.” One is a program and the other is an FKEY; both dump the main screen to disk as a PICT. The FKEY is a more complete sample in the sense that it works in black and white as well as Macintosh color computers, but the other is a smaller and simpler sample.
  5472. Getting the color usage from a picture under System 6
  5473. Date Written:  6/8/92
  5474. Last reviewed:  9/15/92
  5475. Do you know how I can obtain the color table of a picture when using a system version that happens to be less than 7.0? The Picture Utilites package seems to be only implemented in System 7.0.
  5476. ___
  5477. You’re correct; the Picture Utilities package is implemented only under System 7. However, it’s possible to write code to duplicate its functionality under System 6. Basically, what you want to do is parse a picture, looking at the colors used for the different objects. How you deal with the colors is up to you.
  5478. What you do is replace the QuickDraw bottlenecks in a GrafPort with procedures of your own; in all the bottlenecks for QuickDraw primitives, you can just record the current color as having been used for an object. When you get a StdBits opcode, you’ll have to parse the pixmaps, looking through the image and recording all the colors used. As a shortcut, you could just record all the colors in the color table of the pixmap, if it's an indexed pixel image. After collecting this list of colors and any information on how often they are used, it’s up to you to boil this down into useful information, depending on how you want to use it.
  5479. QD 540 - QuickDraw GX Q&As
  5480. QuickDraw    
  5481. Revised by:    Developer Support Center    September 1993
  5482. Written by:    Developer Support Center    October 1990
  5483. This Technical Note contains a collection of Q&As relating to a specific topic—questions you’ve sent the Developer Support Center (DSC) along with answers from the DSC engineers. While DSC engineers have checked the Q&A content for accuracy, the Q&A Technical Notes don’t have the editing and organization of other Technical Notes. The Q&A function is to get new technical information and updates to you quickly, saving the polish for when the information migrates into reference manuals.
  5484. Q&As are now included with Technical Notes to make access to technical updates easier for you. If you have comments or suggestions about Q&A content or distribution, please let us know by sending an AppleLink to DEVFEEDBACK. Apple Partners may send technical questions about Q&A content to DEVSUPPORT for resolution.
  5485. New Q&As for this month:
  5486. QuickDraw GX doesn’t replace QuickDraw
  5487. QuickDraw GX and QuickDraw accelerated display cards
  5488. QuickDraw GX doesn’t replace QuickDraw
  5489. Date Written:  12/11/92
  5490. Last reviewed: 7/2/93
  5491. Will QuickDraw and QuickDraw GX coexist, or will QuickDraw GX replace QuickDraw?
  5492. ___
  5493. QuickDraw isn’t leaving with the introduction of QuickDraw GX. It’s here to stay. Among other reasons, QuickDraw functions are used extensively by the Macintosh Toolbox and applications. For more information, see the article “Getting Started With QuickDraw GX” in issue 15 of develop.
  5494. QuickDraw GX and QuickDraw accelerated display cards
  5495. Date Written:   6/16/92
  5496. Last reviewed: 7/2/93
  5497. Will display cards that offer QuickDraw acceleration be affected by QuickDraw GX?
  5498. ___
  5499. Current QuickDraw acceleration cards aren’t affected by QuickDraw GX. QuickDraw GX doesn’t use any of the current QuickDraw calls and its presence won’t affect applications that use only QuickDraw. QuickDraw acceleration cards also won’t accelerate QuickDraw GX.
  5500. ◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  5501. /ZÅ#
  5502.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  5503. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  5504. .WIQkWIQk+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  5505. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  5506. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  5507.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  5508. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  5509. IR.°dONLNdo<Ç–(úZ.QD 1 - 32-Bit QuickDraw:  Version 1.2 Features
  5510. °dONLNd/Å<êá*    QuickDraw
  5511. °dONLNd:ú<®q* Written by:°dONLNdFúÑ®Œ)HGuillermo Ortiz°dONLNdVúÀ®˛(ƒÈ
  5512. April 1990°dONLNda¥<¿Á(‹ZOThis Technical Note describes the changes and enhancements to 32-Bit QuickDraw °dONLNd∞¥Á¿˛(‹from°dONLNdµ¿<Ãb(ËZversion °dONLNdΩ¿bÃ˛)&S1.0 (as shipped on the original Color Disk) to version 1.2, which ships with System°dONLNdÃ<ÿR(ÙZ9Software 6.0.5 and later.  This Note assumes familiarity °dONLNdJÃRÿl(Ùpwith °dONLNdOÃlÿø)Inside Macintosh°dONLNd_Ãøÿ˛)S , Volume V,°dONLNdkÿ<‰E(Z4Color QuickDraw, and 32-Bit QuickDraw release notes. X
  5513. °dONLNd†    <∂*432-Bit QuickDraw
  5514. °dONLNd±$<0®*GVersion 1.0 of 32-Bit QuickDraw shipped in May 1989 in response to the °dONLNd¯$®0˛(LΔgrowing need for°dONLNd    0<<Z(XZColor °dONLNd0Z<˛)TQuickDraw support for direct color devices and pictures (PICT2) and video boards for°dONLNdd<<Hy(dZ
  5515. large-screen °dONLNdq<yH˛)=Mmonitors which require 32-bit addressing for black and white operation.  This°dONLNdøH<T(pZ]original version of 32-Bit QuickDraw was a separate file that had to be copied manually into °dONLNdHT˛(pthe°dONLNd T<`(|Z-System Folder.  With the introduction of the °dONLNdMT`˛)‘/Macintosh IIci, Apple put 32-Bit QuickDraw into°dONLNd}`<lÃ(àZPROM.  Now System Software 6.0.5 and later offer 32-Bit QuickDraw as an integral °dONLNdÕ`Ãl˛(àÍ part of the°dONLNdŸl<xÉ(îZASystem Software which can be installed by the standard Installer °dONLNdlÉx˛(î°(although the file is still°dONLNd6x<Ñj(†Z
  5516. separate).°dONLNdAê<ún*
  5517. This Note °dONLNdKênú˛)2Ndescribes the changes and enhancements in version 1.2 of 32-Bit QuickDraw from°dONLNdöú<®Õ(ƒZversion 1.0.  Beginning with °dONLNd∑úÕ®˛)ë>version 1.2, QuickDraw functionality is identical on all Color°dONLNdˆ®<¥ˆ(–Z&QuickDraw machines, including all the °dONLNd®ˆ¥˛)∫3performance improvements which were originally only°dONLNdP¥<¿∂(‹Zavailable in the IIci ROM.
  5518. °dONLNdkÿ<ÁB*'%New Features (In No Particular Order)
  5519. °dONLNdëÛ<ˇ*#PICTs Contain Font Name Information°dONLNdµ <*&Every time you draw text inside of an ,
  5520. Courier°dONLNd€ d)‘ _OpenPicture°dONLNdÁ dÖ)T and °dONLNdÏ Ö‡)!
  5521. _ClosePicture°dONLNd˘ ‡˛)[ pair,°dONLNd<$E(@Z7QuickDraw stores the name of the current font and uses °dONLNd7E$˛(@c&it when playing back the picture.  The°dONLNd^$<0ë(LZIopcode used to save this information is $002C and its data is as follows:
  5522.     °dONLNd®<<Gπ*    PictFontInfo = Record°dONLNd¬F<Qü*
  5523. G                     length   : Integer;    { length of data in bytes }°dONLNd
  5524. P<[ü*
  5525. G                     fontID   : Integer;    { ID in the source system }°dONLNdRZ<eˇ*
  5526. '                     fontName : Str255;°dONLNdzd<oØ*
  5527.                    END; ¡X¡
  5528. *K.QD 1 - 32-Bit QuickDraw:  Version 1.2 Features(÷1) of 5(ÏZM.QD.32BitQuickDrawˇ°¿Ù%%DSIDICT:_cv
  5529. currentdict /bu known {bu}if
  5530. userdict /_cv known not{userdict /_cv 30 dict put}if
  5531. _cv begin
  5532. /bdf{bind def}bind def
  5533. currentscreen/cs exch def/ca exch def/cf exch def
  5534. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  5535. /ss{//cf //ca //cs setscreen}bdf
  5536. /stg{ss setgray}bdf
  5537. /strgb{ss setrgbcolor}bdf
  5538. /stcmyk{ss cvcmyk}bdf
  5539. /min1{dup 0 eq{pop 1}if}bdf
  5540. end
  5541. currentdict /bn known {bn}if
  5542. †ø˛◊#ˇ ˇˇˇˇ#◊ 
  5543. IR,Times
  5544. .+6-Macintosh Technical Notes /4/˘
  5545. °dONLNd)¢*QuickDraw only saves this °dONLNd¢)⁄)ä;information one time for each font used in a picture.  When°dONLNdV*6æ(R6#QuickDraw plays back a picture, it °dONLNdy*æ6È)¶    uses the ,
  5546. Courier°dONLNdÇ)È5)+fontID°dONLNdà*6⁄)*+ as a reference into the list of font names°dONLNd¥6B*(^6<which are used to set the correct font on the target system.°dONLNdÒNZµ* For example, the following code:
  5547.     °dONLNdfqv*F    GetFNum('Venice', theFontID);    { Set a font before opening PICT}°dONLNdYp{ê*
  5548.     TextFont(theFontID);°dONLNdrÑè—*%    pHand2 := OpenPicture (pictRect);°dONLNdòéôÜ*
  5549.         MoveTo(20,20);°dONLNdØò£‡*
  5550. (        DrawString(' Better be Venice');°dONLNdÿ¨∑—*%        GetFNum('Geneva', theFontID);°dONLNd˛∂¡§*
  5551.         TextFont(theFontID);°dONLNd¿ÀÜ*
  5552.         MoveTo(20,40);°dONLNd2 ’©*
  5553.         DrawString('Geneva');°dONLNdPfiÈ€*'        GetFNum('New York', theFontID);°dONLNdxËÛ§*
  5554.         TextFont(theFontID);°dONLNdïÚ˝Ü*
  5555.         MoveTo(20,60);°dONLNd¨¸≥*
  5556.         DrawString('New York');°dONLNd×*%        GetFNum('Geneva', theFontID);°dONLNdÚ%§*
  5557.         TextFont(theFontID);°dONLNd$/Ü*
  5558.         MoveTo(20,80);°dONLNd&.9©*
  5559.         DrawString('Geneva');°dONLNdD8Cm*
  5560.     ClosePicture;
  5561. °dONLNdWNZ*:generates a picture containing font information like this:
  5562.     °dONLNdífqÅ*    OpCode 0x002C {9,°dONLNd©p{ä*
  5563. J        "0005 0656 656E 6963 65"}              /* save current font     */°dONLNdÙzÖw*
  5564.     TxFont 'venice'°dONLNdÑèÍ*
  5565. *    DHDVText {20, 20, " Better be Venice"}°dONLNd3éôä*
  5566. J    OpCode 0x002C {9,                          /* save next font name   */°dONLNd~ò£Ω*
  5567. !        "0003 0647 656E 6576 61"}°dONLNd†¢≠w*
  5568.     TxFont 'geneva'°dONLNd¥¨∑ï*
  5569.     DVText {20, "Geneva"}°dONLNdŒ∂¡ä*
  5570. J    OpCode 0x002C {11,                         /* ditto                 */°dONLNd¿À÷*
  5571. &        "0002 084E 6577 2059 6F72 6B"}°dONLNd@ ’|*
  5572.     TxFont 'newYork'°dONLNdU‘flü*
  5573.     DVText {20, "New York"}°dONLNdqfiÈÄ*
  5574. H    TxFont 'geneva'                            /* second Geneva does not°dONLNd∫ËÛä*
  5575. J                                                 need another $002C guy */°dONLNdÚ˝ï*
  5576.     DVText {20, "Geneva"}
  5577. °dONLNd•*VThis feature works regardless of the type of picture being saved, including old style °dONLNdu•⁄(0√
  5578. PICTs in a°dONLNdÄ!¥(=6black and white port.  Using °dONLNdù¥ )ú
  5579. _OpenCPicture°dONLNd™!O)[  instead of °dONLNd∂O £)@ _OpenPicture°dONLNd¬£!⁄)T  to start a°dONLNdŒ!-(I64recording session results in the same functionality.°dONLNd9E˛*&Direct PixPat Structures Now Supported°dONLNd*R^*3QuickDraw now supports 16-bit and 32-bit per pixel °dONLNd]Q]=)˚PixPat°dONLNdcR=^u)*
  5580.  structures (°dONLNdpQu]¬)8 patType = 1°dONLNd{R¬^–)M).  °dONLNdR–^⁄)In°dONLNdÇ_k±(á6 addition, it now supports a new °dONLNd¢^±j‚)ôpatType°dONLNd©_‚kˆ)1 (3) °dONLNdÆ_ˆk⁄).which uses dithering whenever 16-bit or 32-bit°dONLNdfikw˘(ì60pixel patterns are displayed on indexed devices. ¡4¡˘
  5581. *C2) of 5)˘.QD 1 - 32-Bit QuickDraw:  Version 1.2 Features+dM.QD.32BitQuickDrawˇ◊#ˇ ˇˇˇˇ#◊ 
  5582. IR,Times
  5583. .+Z-Developer Support Center(-
  5584. April 1990 /X/
  5585. °dONLNd)<5(QZ%Direct 'cicn' Resources Now Supported°dONLNd&B<N7*3QuickDraw now supports 16-bit and 32-bit per pixel ,
  5586. Courier°dONLNdYA7Ma)˚'cicn'°dONLNd_BaN˛)*! resources.  The 16-bit per pixel°dONLNdÅO<[n(wZDis particularly cool since you save the space required for an 8-bit °dONLNd≈NnZò(wå'clut'°dONLNdÀOò[ú)*.°dONLNdÕg<sΩ(èZ<GWorlds Can Now Be Allocated in MultiFinder Temporary Memory°dONLNd
  5587. Ä<åS*You °dONLNdÄSåæ)can now use the new °dONLNd"æã)k
  5588. useMFTempBit °dONLNd/Äås)\(bit 2) in a call to °dONLNdDsã≤)Y    NewGWorld°dONLNdMÄ≤å˛)? as an option to°dONLNd^å<ò/(¥Z1allocate pixels in MultiFinder temporary memory. °dONLNdèå/ò˛)Û) In addition, you can now allocate screen°dONLNdπò<§˛(¿Z]buffers in MultiFinder temporary memory using the following routine, defined in Pascal and C:
  5589.     °dONLNd∞<ªã*CFUNCTION NewTempScreenBuffer (globalRect: Rect; purgeable: BOOLEAN;°dONLNd[∫<≈,*
  5590. 0                              VAR gdh: GDHandle;°dONLNdåƒ<œ©*
  5591. I                               VAR offscreenPixMap: PixMapHandle): QDErr;°dONLNd÷Œ<Ÿê*
  5592. D             INLINE $203C,$000E, $0015,$AB1D; { Move.L #$000E0015,D0°dONLNdÿ<„c*
  5593. ;                                               _QDOffscreen°dONLNdW‚<Ì"*
  5594. .                                             }°dONLNd܈<ö*Fpascal QDErr NewTempScreenBuffer (Rect *globalRect, BOOLEAN purgeable,°dONLNdÕ< *
  5595. ,                              GDHandle *gdh,°dONLNd˙
  5596. <h*
  5597. <                              PixMapHandle *offscreenPixMap)°dONLNd7<*
  5598. ,             ={0x203C,0x000E,0x0015,0xAB1D};
  5599. °dONLNde*<6‚*Indexed to Indexed Dithering°dONLNdÇB<N{*    _CopyBits°dONLNdãC{Oñ)? now °dONLNdêCñO’)
  5600. supports the °dONLNdùB’N)?
  5601. ditherCopy°dONLNdßCO˛)F. transfer mode whenever the destination device°dONLNd÷O<[7(wZ7is between one and eight bits per pixel, regardless of °dONLNd
  5602. O7[˛)˚)the depth of the source image.  With this°dONLNd7[<gä(ÉZFsupport, an eight-bit image can now be approximated on a one-bit or a °dONLNd}[äg˛(É®four-bit device by using°dONLNdñg<sÕ(èZXerror diffusion.  Furthermore, an eight-bit image could also be dithered to a different °dONLNdÓgÕs˛(èÎ
  5603. set of 256°dONLNd˘s<ù(õZNcolors or a four-bit image could be dithered to an eight-bit device that does °dONLNdGsù˛(õªnot have the desired°dONLNd\<ã](ßZcolors.°dONLNddó<£ *"32-Bit Addressed PixMap Structures°dONLNdá∞<º§*Version 1.2 defines a °dONLNdù∞§ºº)hnew °dONLNd°غª˚)    pmVersion°dONLNd™∞˚º)? (°dONLNd¨Øªg)baseAddr32 = 4°dONLNd∫∞gºΔ)d) for 32-bit pointer °dONLNdœØΔª˛)_baseAddr°dONLNdÿΩ<…(ÂZ
  5604. values.  The °dONLNdº»∑)CbaseAddr°dONLNdÌΩ∑…Ê)8     of such °dONLNdˆºÊ»)/PixMap°dONLNd¸Ω…≥)*# structures is treated as a 32-bit °dONLNdΩ≥…˛)£address, so no°dONLNd.…<’ú(ÒZJstripping or address translation is performed on it in 32-bit mode.  This °dONLNdx…ú’˛(Ò∫is a specially useful°dONLNdé÷<‚Ë(˛Z#feature when the base address of a °dONLNd±’Ë·)¨PixMap°dONLNd∑÷‚)* °dONLNd∏÷‚r)points to a NuBus
  5605.     °dONLNd…‘rflz(˚ê™
  5606. °dONLNd ÷z‚˛+ address, for example in a°dONLNd‚<Óü(
  5607. Zvideo grabber board.°dONLNd˙˚<x* A new call, °dONLNd˙x≈)< Pixmap32Bit°dONLNd˚≈)M, is now available °dONLNd$˚à)Zto inquire if a given °dONLNd:˙à≤)iPixMap°dONLNd@˚≤˛)* requires 32-bit°dONLNdQ<s(/Z addressing.
  5608.     °dONLNd]<*'*/FUNCTION Pixmap32Bit(pmh:pixMapHandle):Boolean;°dONLNdç)<4c*
  5609. ;    INLINE $203C,$0004, $0016,$AB1D; { Move.L #$00040016,D0°dONLNd…3<>6*
  5610. 2                                      _QDOffscreen°dONLNd¸=<Hı*
  5611. %                                    }°dONLNd    "Q<\*,pascal BOOLEAN Pixmap32Bit(pixMapHandle pmh)°dONLNd    O[<fı*
  5612. %    = {0x203C,0x0004, 0x0016,0xAB1D}; ¡X¡
  5613. *T.QD 1 - 32-Bit QuickDraw:  Version 1.2 Features(÷3) of 5(ÏZM.QD.32BitQuickDrawˇr◊#ˇ ˇˇˇˇ#◊ 
  5614. IR,Times
  5615. .+6-Macintosh Technical Notes /4/˘
  5616. °dONLNd)5ª*$Updated GetPixBaseAddress°dONLNdBNÄ*Version 1.2 updates ,
  5617. Courier°dONLNd.AÄM˜)hGetPixBaseAddress°dONLNd?B˜Ng)w to return the address °dONLNdVBgNé)pof any °dONLNd]AéM∏)'PixMap°dONLNdcB∏N⁄)*.  The°dONLNdjO[G(w6@routine does the right address translation or stripping for all °dONLNd™NGZq(wePixMap°dONLNd∞Oq[v)* °dONLNd±Ov[⁄)structures, including°dONLNd«\hc(Ñ6screen devices, °dONLNd◊\ch.)K'unlocked GWorlds, and 32-bit addressed °dONLNd˛[.gX)ÀPixMap°dONLNd\Xh⁄)* structures.  The address it°dONLNd!iuG(ë6 returns is °dONLNd,iGuO)/6only valid in 32-bit addressing mode. Also unless the °dONLNdbhOty(ëmPixMap°dONLNdhiyu⁄)* is locked and made°dONLNd|vÇœ(û6%unpurgeable, the address returned by °dONLNd°uœÅF)∑GetPixBaseAddress°dONLNd≤vFÇV)w is °dONLNd∂vVÇ⁄)only valid until any call to°dONLNd”Çéæ(™6!QuickDraw or the toolbox is made.°dONLNdıö¶Õ*_CopyBits from Screen Devices°dONLNd≥ø*4The picture recording mechanism has changed so that °dONLNdG≥øL)ˇ if you call °dONLNdS≤Læã)5    _CopyBits°dONLNd\≥ãø⁄)? while recording°dONLNdm¿Ãé(Ë6a picture with the source °dONLNdáøéÀ∏)vPixMap°dONLNdç¿∏Ç)*     being a °dONLNdñ¿‡Ã⁄)(5screen device, the data is correctly accumulated into°dONLNdÃÕŸ*(ı6>the picture.  Note that if the screen being copied is not the °dONLNd
  5618. Õ*Ÿï(ıHmain screen, then the °dONLNd Ãïÿø)kPixMap°dONLNd&ÕøŸ⁄)* must°dONLNd,⁄Ê(6be a 32-bit addressed °dONLNdBŸ©)gPixMap°dONLNdH⁄©Ê∞)*. °dONLNdJ⁄∞Ê⁄)@ No auxiliary screen buffer is allocated if the source rectangle°dONLNdãÊÚà(6covers only one screen.°dONLNd£˛
  5619. ∫*New Picture Recording Trap°dONLNdæ#x*Version 1.2 adds a °dONLNd—x#™)`
  5620. new call, °dONLNd€™")2
  5621. _OpenCPicture°dONLNdË#⁄)[-, to create pictures that contain information°dONLNd#/Ù(K60regarding the native resolution of the recorded °dONLNdF#Ù/⁄)‹-image.  When QuickDraw draws this picture, it°dONLNdt/;†(W6Qscales the image to the resolution of the target device.  Applications that need °dONLNd≈/†;⁄(Wæ to scale the°dONLNd“;G˚(c61images directly can also access this information.
  5622.     °dONLNdS^?*;FUNCTION OpenCPicture(VAR CPictInfo:CPictRecord):PicHandle;°dONLNd@]hm*
  5623.     INLINE $AA20;°dONLNdRq|!*5pascal PicHandle OpenCPicture(CPictRecord *CPictInfo)°dONLNdà{Ü^*
  5624.     =  0xAA20;
  5625. °dONLNdóëù5*where
  5626.     °dONLNdù©¥|*struct CPictRecord {°dONLNd≤≥æ∑*
  5627. S      Rect CPicFrame;           /* Bounding rect of Picture at native resolution */°dONLNdΩ»∑*
  5628. S      Fixed CPicHRes;           /* native horizontal resolution in pixels/inch   */°dONLNdZ«“∑*
  5629. S      Fixed CPicVRes;           /* native vertical resolution in pixels/inch     */°dONLNdÆ—‹∑*
  5630. S      short CPicVersion;        /* version of this PICT info set to -2           */°dONLNd€Ê∑*
  5631. S      short reserved;           /* for future expansion set to zero              */°dONLNdVÂ∑*
  5632. S      long reserved;            /* for future expansion set to zero              */°dONLNd™Ô˙J*
  5633.  
  5634.         };
  5635. °dONLNdµ*5The new picture header data looks like the following:°dONLNdÎ`)©+H
  5636. Size in bytes°dONLNd˘√)„)cName°dONLNd˛/)p)l Description H|Hµ°dONLNd +7Ö(Sù2°dONLNd
  5637. *√6Ù)DpicSize°dONLNd+7ê)Zlow word of picture size°dONLNd/8DÖ(`ù8°dONLNd17√C˚)DpicFrame°dONLNd:8Dã)Zbounding box at 72 dpi c|cµ ¡4¡˘
  5638. (÷64) of 5)˘.QD 1 - 32-Bit QuickDraw:  Version 1.2 Features+dM.QD.32BitQuickDrawˇJ◊#ˇ ˇˇˇˇ#◊ 
  5639. IR,Times
  5640. .+Z-Developer Support Center(-
  5641. April 1990 /X/
  5642. °dONLNd)`5¥(Q~Picture Header T|TÁ°dONLNd7`Cf*2,
  5643. Courier°dONLNd6çB”)-
  5644. version op°dONLNd7Cc)cversion opcode = $0011°dONLNd3D`Pf(l~2°dONLNd5CçOæ)-version°dONLNd=DPg)cversion number = $02FF°dONLNdTQ`]f(y~2°dONLNdVPç\Ã)-    Header op°dONLNd`Q]d)cheader opcode  = $0C00°dONLNdw^`jf(Ü~2°dONLNdy]çiæ)-version°dONLNdÅ^jl)c-2 for PICTs created with °dONLNdõ]li«)|
  5645. _OpenCPicture°dONLNd©k`wf(ì~2°dONLNd´jçv≈)-reserved°dONLNd¥x`Ñf(†~4°dONLNd∂wçÉ©)-HRes°dONLNdªxÑw)cnative horizontal resolution (°dONLNdŸwwÉö)áFixed°dONLNdfixöÑû)#)°dONLNd‡Ö`ëf(≠~4°dONLNd‚Ñçê©)-VRes°dONLNdÁÖëj)cnative vertical resolution (°dONLNdÑjêç)zFixed°dONLNdÖçëë)#)°dONLNd
  5646. í`ûf(∫~8°dONLNd ëçùæ)-SrcRect°dONLNdíû[)cnative source rectangle°dONLNd,ü`´f(«~4°dONLNd.ûç™≈)-reserved  | Á°dONLNd7≈<—(ÌZ,The following is a sample PICT created with °dONLNdcƒ–m)÷
  5647. _OpenCPicture°dONLNdp≈m—p)[:
  5648.     °dONLNdr›<Ëö(ZF    00 48                          /* low word of size              */°dONLNdπÁ<Úö*
  5649. F    00 00 00 00 00 7D 00 7D        /* picFrame at 72 dpi            */°dONLNdÒ<¸ö*
  5650. F    00 11                          /* PICT version opcode           */°dONLNdG˚<ö*
  5651. F    02 FF                          /* version number                */°dONLNdé<ö*
  5652. F    0C 00                          /* PICT header Opcode            */°dONLNd’<ö*
  5653. F    FF FE                          /* PICT version -2               */°dONLNd<$ö*
  5654. F    00 00                          /* reserved                      */°dONLNdc#<.ö*
  5655. F    01 20 00 00                    /* HRes (Fixed)                  */°dONLNd™-<8ö*
  5656. F    01 20 00 00                    /* VRes (Fixed)                  */°dONLNdÒ7<Bö*
  5657. F    00 00 00 00 01 F4 01 F4        /* picFrame at native resolution */°dONLNd8A<Lö*
  5658. F    00 00 00 00                    /* reserved                      */°dONLNdK<Vö*
  5659. F    /* picture data follows                                         */°dONLNdΔU<`ö*
  5660. F    00 FF                          /* end of picture opcode         */
  5661. °dONLNd
  5662. w<Üõ*& Random Notes
  5663. °dONLNdí<û‡* For information on bug fixes in °dONLNd:í‡û˛)§5the System Software 6.0.5 release of 32-Bit QuickDraw°dONLNdpû<™≈(ΔZR(version 1.2), please refer to the System Software 6.0.5 Change History, which is °dONLNd¬û≈™˛(Δ„ available on°dONLNdœ™<∂(“Z&the Developer CD Series, AppleLink in °dONLNdı™∂˛)»0the Developer Services Bulletin Board (Developer°dONLNd&∂<¬û(fiZServices: Macintosh °dONLNd:∂û¬˛)bEDeveloper Technical Support: System Software), and the Apple FTP site°dONLNdĬ<Œ(ÍZ/on the Internet in the ~ftp/pub/dts/sw.license.°dONLNd∞€<Á*,Note that the dispatching mechanism for the °dONLNd‹€Á.)Ÿnew °dONLNd‡⁄.ÊÇ) _QDOffscreen°dONLNdÏ€ÇÁ˛)T calls is slightly different°dONLNd    Ë<ÙË(Z#than previously documented; it now °dONLNd,ËËÙ†)¨&requires that the high word passed in °dONLNdRÁ†ÛÆ)∏D0°dONLNdTËÆÙ˛) contain the total°dONLNdgÙ<¸(Z*length of the parameters (in bytes).  The °dONLNdëÙ¸˛)¿8reason for this change is that if the call is made in an°dONLNd < V((Z:earlier version of 32-Bit QuickDraw, the system can strip °dONLNdV ˛((t!the parameters from the stack and°dONLNd&
  5664. <[(5Zreturn °dONLNd- [å)QDError°dONLNd4
  5665. å=)1) set to the caller (instead of crashing).°dONLNd^=<I¶(eZFurther Reference: hXh°dONLNdqJNVR+
  5666. •°dONLNdsJ`V±)Inside Macintosh°dONLNdÉJ±VC)Q, Volume V, Color QuickDraw°dONLNdüVNbR(~l•°dONLNd°V`bm)432-Bit QuickDraw Release Notes (available from APDA)°dONLNd÷bNnR(äl•°dONLNdÿb`n)$System Software 6.0.5 Change History°dONLNd˝nNzR(ñl•°dONLNdˇn`zó)
  5667. d e v e l o p°dONLNd     nózæ)7    , Issue I°dONLNd    Ü<í(ÆZ*NuBus is a trademark of Texas Instruments. ¡X¡
  5668. *(.QD 1 - 32-Bit QuickDraw:  Version 1.2 Features(÷5) of 5(ÏZM.QD.32BitQuickDrawˇf◊#ˇ ˇˇˇˇ#◊†Ç 
  5669. /ZÅ#
  5670.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  5671. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  5672. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  5673. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  5674. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  5675.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  5676. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  5677. IR.°dONLNdn<ÅÈ(õZ)QD 2 - BitMapToRegion : So Many Bitmaps, °dONLNd)nÈŞ(õSo°dONLNd,Ä<ìô(≠Z Little Time
  5678. °dONLNd8í<°á*    QuickDraw
  5679. °dONLNdC≠<πt* Revised by:°dONLNdO≠Ñπ¿)H Rich Collyer°dONLNd\≠¥π˛(’“
  5680. December 1989°dONLNdjπ<≈q(·Z Written by:°dONLNdvπÑ≈¥)H
  5681. Rick Blair°dONLNdÅπÀ≈˛(·È
  5682. April 1988°dONLNdå“<fiT(˙ZThis °dONLNdë“Tfi)%Technical Note discusses the routine ,
  5683. Courier°dONLNd∂—›j)¥BitMapToRegion°dONLNdƒ“jfi˛)b, which converts a bitmap to a°dONLNd„fi<ÍÎ(ZXregion, and is available in the 32-Bit QuickDraw INIT and from Apple Software Licensing.°dONLNd<Í<ˆÁ* Changes since October 1989:°dONLNdWÍÁˆ‡)´2  Added trap definitions for developers using the °dONLNdâ͇ˆ˛)˘32-Bit°dONLNdêˆ<í(ZGQuickDraw version of this routine without the correct MPW include file. -X-°dONLNdÿ<'á*%GThe following routine is now available to convert a bitmap to a region:
  5684.     °dONLNd 3<>r*>FUNCTION BitMapToRegion(region:RgnHandle; bMap:BitMap): OSErr;
  5685. °dONLNd_I<US*in C:
  5686.     °dONLNdea<lc*;pascal OSErr BitMapToRegion(RgnHandle region, BitMap bMap);
  5687. °dONLNd°w<Éò*JIf you are using the 32-Bit QuickDraw version of this routine without the °dONLNdÎwòɲ(ü∂correct MPW include°dONLNdˇÉ<è`(´Z@file, then you need to include one of the following definitions:°dONLNd@õ<ßZ*Pascal
  5688.     °dONLNdG≥<æÅ*AFUNCTION BitMapToRegion (region: RgnHandle; bMap: BitMap): OSErr;°dONLNdâΩ<»™*
  5689.          INLINE $A8D7;
  5690. °dONLNd†”<flD*C
  5691.     °dONLNd¢Î<ˆÜ*Bpascal OSErr BitMapToRegion (RgnHandle region, const BitMap *bMap)°dONLNdÂı<™*
  5692.              = 0xA8D7;
  5693. °dONLNd¸ <k*Assembly
  5694.     °dONLNd#<.**_BitMapToRegion        OPWORD        $A8D7
  5695. °dONLNd0:<Fá*The region will °dONLNd@:áF)K!be built so that all one bits in °dONLNda9E5)íbMap°dONLNde:5F˛), are inside the region and all zero bits are°dONLNdíF<Rx(nZoutside of it.°dONLNd°_<k4*3As with all QuickDraw calls which change a region, °dONLNd‘^4jù)¯BitMapToRegion °dONLNd„_ùkΔ)i    requires °dONLNdÏ_Δk˛)) you to pass°dONLNd¯l<x(îZ*an existing region (originally created by °dONLNd"kw1)ƒ_NewRgn°dONLNd)l1xÅ)1).  If the region °dONLNd;lÅx˛)Pcannot be built due to an°dONLNdUx<Ñò(†ZJinsufficient heap space or a size greater than 32K, then the routine will °dONLNdüxòÑ˛(†∂return an appropriate ¡X¡
  5696. (÷Z7QD 2 - BitMapToRegion : So Many Bitmaps, So Little Time(÷1) of 2(ÏZM.QD.BitMapToRegionˇ°¿Ù%%DSIDICT:_cv
  5697. currentdict /bu known {bu}if
  5698. userdict /_cv known not{userdict /_cv 30 dict put}if
  5699. _cv begin
  5700. /bdf{bind def}bind def
  5701. currentscreen/cs exch def/ca exch def/cf exch def
  5702. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  5703. /ss{//cf //ca //cs setscreen}bdf
  5704. /stg{ss setgray}bdf
  5705. /strgb{ss setrgbcolor}bdf
  5706. /stcmyk{ss cvcmyk}bdf
  5707. /min1{dup 0 eq{pop 1}if}bdf
  5708. end
  5709. currentdict /bn known {bn}if
  5710. †øˆ◊#ˇ ˇˇˇˇ#◊ 
  5711. IR,Times
  5712. .+6-Macintosh Technical Notes /4/˘
  5713. °dONLNd)≠*Uerror code and the region will be empty.  If the region would have exceeded 32K, the °dONLNdU≠)⁄(EÀ
  5714. error will°dONLNd`*6&(R6be ,
  5715. Courier°dONLNdc)&5z) rgnTooBigErr°dONLNdo*z6ü)T (-500).°dONLNdxBN∞(j6SThis function is useful for a number of situations where you have (or can produce) °dONLNdÀB∞N⁄(jŒa bitmap°dONLNd‘O[Ä(w6representing an area.  °dONLNdÎOÄ[¿)h You can use °dONLNd˜N¿Zˇ)@    _CalcMask°dONLNdOˇ[⁄)?+ to produce such a bitmap.  Once you have a°dONLNd,\he(Ñ6region, you can °dONLNd<\eh)M!perform region operations (i.e., °dONLNd][g:)ù_PtInRgn°dONLNde\:hB)8, °dONLNdg[BgÅ)    _UnionRgn°dONLNdp\Åhó)?, or °dONLNdu[óg÷)    _InsetRgn°dONLNd~\÷h⁄)?)°dONLNdÄiu8(ë6or call °dONLNdàh8tå)  _DragGrayRgn°dONLNdîiåuœ)T, for example.°dONLNd£ÅçY(©6CThis call is part of the 32-Bit QuickDraw INIT ($A8D7).  If you do °dONLNdÊÅYç÷(©wnot wish to depend on 32°dONLNd˛Å÷ç⁄)}-°dONLNdˇéö)(∂6Bit °dONLNdé)ö),QuickDraw, then you can obtain a version of °dONLNd/çôj)flBitMapToRegion°dONLNd=éjö⁄)b in MPW object format°dONLNdSö¶™(¬6Pwhich can be linked into an MPW program, by contacting Apple Software Licensing:°dONLNdß≤Ñæˇ+lApple Software Licensing°dONLNd√æÑ * Apple Computer, Inc.,°dONLNd‹ Ñ÷"* 20525 Mariani Avenue, M/S 38-I°dONLNd˛÷Ñ‚Ô* Cupertino, CA, 95014°dONLNd‚ÑÓœ* (408) 974-4667°dONLNd(ÓÑ˙* AppleLink:  SW.LICENSE°dONLNd?(/63If you licensed the older version of this routine, °dONLNdrM)ˆ    BitMapRgn°dONLNd{M¨)?, contact Software °dONLNdé¨⁄)_    Licensing°dONLNdò(;62about receiving an updated version.  We recommend °dONLNd ⁄(;9&you update your application to use the°dONLNdÒ+¥(G6 new version as soon as possible.°dONLNd8DØ*The new version is now named °dONLNd/7ØC)óBitMapToRegion°dONLNd=8DØ)b# to be consistent with the version °dONLNd`8ØD⁄)û    in 32-Bit°dONLNdjEQ“(m6#QuickDraw and the MPW interfaces.  °dONLNdçE“Q)∫
  5716. In addition, °dONLNdöDPr)>BitMapToRegion°dONLNd®ErQ⁄)b offers new features.°dONLNdøQ]v(y6You can now pass °dONLNd–Qv]⁄)^Ea one-bit pixelmap which has been coerced to a bitmap.  If you pass a°dONLNd^j˚(Ü61pixelmap which is too large, then you will get a °dONLNdG]˚ik)„pixmapTooDeepErr°dONLNdW^kjè)p (-148) °dONLNd_^èj⁄)$error.  You can°dONLNdokwW(ì6also pass the °dONLNd}jWvè)?portBits°dONLNdÖkèwä)84 of a window, much like you would do with a call to °dONLNdπjäv…)˚    _CopyBits°dONLNd¬k…wÕ)?.°dONLNdƒÉè?(´6>There is a potential problem with this routine, since MPW 3.1 °dONLNdÉ?è⁄(´]!include files contain information°dONLNd$êú◊(∏6%about 32-Bit QuickDraw.  If you want °dONLNdIè◊õ9)øBitMapToRegion°dONLNdWê9ú=)b °dONLNdXê=ú⁄) to be available on all machines,°dONLNdyú®ß(ƒ6then you must use the object °dONLNdñúß®⁄)è;file from Software Licensing.  The problem is that when you°dONLNd“®¥í(–6Mcompile your application with MPW 3.1 or later, the 32-Bit QuickDraw version °dONLNd®í¥⁄(–∞gets preference°dONLNd/¥¿ê(‹6over the object file.  You °dONLNdJ¥ê¿´)xmust°dONLNdN¥´¿ˇ) comment out the °dONLNd_¥ˇ¿⁄)T/routine in the include files if you want to use°dONLNdè¡ÕÅ(È6the object file.  If you °dONLNd®¡ÅÕÌ)ionly care about using °dONLNdæ¿ÌÃO)lBitMapToRegion°dONLNdáOÕ⁄)b on machines running 32-Bit°dONLNdËÕŸË(ı6)QuickDraw, then you need not do anything. ¡4¡˘
  5717. *·2) of 2)ƒ7QD 2 - BitMapToRegion : So Many Bitmaps, So Little Time+ñM.QD.BitMapToRegionˇ™◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  5718. /ZÅ#
  5719.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  5720. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  5721. .WIQkWIQk+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  5722. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  5723. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  5724.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  5725. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  5726. IR.°dONLNdˇˇ(úZ-QD 3 - Color Cursor Cursing : A Leading Cause
  5727. °dONLNdˇˇ*    QuickDraw
  5728. °dONLNdˇˇ* Revised by:°dONLNdˇˇ)H
  5729. Alan Mimms°dONLNdˇˇ(ƒ‹ October 1989°dONLNdˇˇ(–Z Written by:°dONLNdˇˇ)H
  5730. Alan Mimms°dONLNdˇˇ(–Π   June 1989°dONLNdˇˇ(ËZIWorking with color cursors you create from scratch can cause headaches.  °dONLNdˇˇ(˪This Technical Note°dONLNdˇˇ(ÙZmay help a bit.°dONLNdˇˇ*
  5731. Changes since June 1989:°dONLNdˇˇ)ì"  Added a warning about purgeable ,
  5732. Courier°dONLNdˇˇ)®'clut'°dONLNdˇˇ)*  resources. X°dONLNdˇˇ(&Z'If you’re building an application that °dONLNdˇˇ)µ4creates color cursors, you may encounter some quirks°dONLNdˇˇ(2ZOpresent in Color QuickDraw that manifest themselves in hard-to-understand ways.°dONLNdˇˇ*If your cursor is, say, 15 °dONLNdˇˇ)Ä@pixels tall and 9 pixels wide, you might be tempted to use these°dONLNdˇˇ(WZvalues for the °dONLNdˇˇ)F
  5733. bounds.bottom°dONLNdˇˇ)[ and °dONLNdˇˇ) bounds.right°dONLNdˇˇ)T, respectively, °dONLNdˇˇ)Hin your cursor’s pixel°dONLNdˇˇ(cZmap.  °dONLNdˇˇ)Don’t°dONLNdˇˇ) .  The problem is that when °dONLNdˇˇ)Ö3the cursor’s image needs to be expanded (i.e., when°dONLNdˇˇ(oZyou °dONLNdˇˇ)Wspecify a two bit-per-pixel cursor and the mouse pointer is on an eight-bit screen) the°dONLNdˇˇ(|Z _SetCCursor°dONLNdˇˇ)M trap rounds the °dONLNdˇˇ)M=width of the pixel map in such a way that you’ll get only the°dONLNdˇˇ(àZspace °dONLNdˇˇ)Rrequired for a 15 by 8 pixel map allocated for the expanded cursor data.  When the°dONLNdˇˇ(îZ%cursor’s image is expanded into this °dONLNdˇˇ)≠8too-small expanded cursor data handle as a 15 by 9 pixel°dONLNdˇˇ(†Z-map, something in your heap will get munched. °dONLNdˇˇ*The cure is simple. 
  5734. °dONLNdˇˇ)çMake °dONLNdˇˇ)*certain°dONLNdˇˇ)&! that you always specify that the°dONLNdˇˇ(≈ZpixmapHandle^^.bounds°dONLNdˇˇ)ì be 16 by 16. °dONLNdˇˇ)L This will cause °dONLNdˇˇ)Y _SetCCursor°dONLNdˇˇ)M  to properly°dONLNdˇˇ(—Zallocate the expanded data °dONLNdˇˇ)ÅAarea, and all will be well in the land.  Since the amount of data°dONLNdˇˇ(fiZdrawn°dONLNdˇˇ)# for °dONLNdˇˇ)7a cursor is specified by the cursor’s pixel values and °dONLNdˇˇ(fiï'clut'°dONLNdˇˇ)* resource, trying to°dONLNdˇˇ(ÍZFsave a few bytes by making the bounds rectangle smaller than 16 by 16 °dONLNdˇˇ(ͪwouldn’t have been°dONLNdˇˇ(ˆZvery helpful anyway.°dONLNdˇˇ*;Another potential problem is with the color cursor’s color °dONLNdˇˇ(u#table.  If you load the color table°dONLNdˇˇ(Zfrom °dONLNdˇˇ)a °dONLNdˇˇ)
  5735. 'clut'°dONLNdˇˇ)* resource using °dONLNdˇˇ)Q
  5736. _GetCTable°dONLNdˇˇ)F , you should make sure that the °dONLNdˇˇ)•'clut'°dONLNdˇˇ)* is°dONLNdˇˇ('Z,marked non-purgeable while the color cursor °dONLNdˇˇ)›/is in use.  If you do not take this precaution,°dONLNdˇˇ(4Zbombs will occur if your °dONLNdˇˇ)x'clut'°dONLNdˇˇ)*$ gets purged at in inopportune time. ¡X¡
  5737. (÷ZQD 3 - 
  5738.     )&Color Cursor Cursing : A Leading Cause
  5739. (÷1) of 1(ÏZM.QD.ColorCursorCursingˇ°¿Ù%%DSIDICT:_cv
  5740. currentdict /bu known {bu}if
  5741. userdict /_cv known not{userdict /_cv 30 dict put}if
  5742. _cv begin
  5743. /bdf{bind def}bind def
  5744. currentscreen/cs exch def/ca exch def/cf exch def
  5745. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  5746. /ss{//cf //ca //cs setscreen}bdf
  5747. /stg{ss setgray}bdf
  5748. /strgb{ss setrgbcolor}bdf
  5749. /stcmyk{ss cvcmyk}bdf
  5750. /min1{dup 0 eq{pop 1}if}bdf
  5751. end
  5752. currentdict /bn known {bn}if
  5753. †ø4◊#ˇ ˇˇˇˇ#◊†Ç 
  5754. /ZÅ#
  5755.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  5756. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  5757. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  5758. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  5759. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  5760.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  5761. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  5762. IR.°dONLNdn<ÅR(õZQD 4 - Colorizing With CopyBits
  5763. °dONLNd Ä<èá*    QuickDraw
  5764. °dONLNd+õ<ßq*
  5765. Revised by°dONLNd7õ≈߲(√„
  5766. March 1988°dONLNdBß<≥q(œZ Written by:°dONLNdNßÑ≥≈)H
  5767. Chris Derossi°dONLNd\ß±≥˛(œœ
  5768. November 1987°dONLNdjø<À¿(ÁZInside Macintosh Volume V°dONLNdÉø¿ÀQ)Ñ  states that the foreground and °dONLNd£øQÀ˛)ë#background colors are applied to an°dONLNd«Ã<ÿÖ(ÙZimage during a ,
  5769. Courier°dONLNd÷ÀÖ◊Ω)ICopyBits°dONLNdfiÃΩÿÕ)8 or °dONLNd‚ÀÕ◊)CopyMask°dONLNdÍÃÿá)8 call. Accidental use of this °dONLNdÃáÿ˛)Çfeature can create bizarre°dONLNd#ÿ<‰ˆ(Z\coloring effects. This note explains what happens, how to avoid problems, and how to use it. X
  5770. °dONLNdÄ    <ô*4 What Happens
  5771. °dONLNdç$<0Æ*Color QuickDraw has a °dONLNd£$Æ0˛)rDfeature that will allow you to convert a monochrome image to a color°dONLNdË1<=ã(YZimage. During a °dONLNd¯0ã<√)OCopyBits°dONLNd1√=Δ)8 °dONLNd1Δ=‘)or °dONLNd0‘< )CopyMask°dONLNd 1 =˛)82 call, if the foreground and background colors are°dONLNd?=<I‘(eZTnot black and white, respectively, Color QuickDraw performs the following operation °dONLNdì=‘I˛(eÚon every°dONLNdúI<Uï(qZpixel being copied:
  5772.     °dONLNd±b`m+$%NOTE: color table index = pixel value°dONLNdÿv`Å*%s = color table index of source pixel°dONLNdˇÄ`ã2*
  5773. *fg = color table index of foreground color°dONLNd+ä`ï2*
  5774. *bg = color table index of background color°dONLNdWû`©U*1ColoredPixelValue = (NOT(s) AND bg) OR (s AND fg)
  5775. °dONLNdâ¥<¿0(‹Z3If your source image contains only black and white °dONLNdº¥0¿˛)Ù*pixels, then all black pixels would become°dONLNdÁ¿<ÃF(ËZ7the foreground color and all white pixels would become °dONLNd¿FÃ˛(Ëd%the background color. This is because°dONLNdDÃ<ÿ◊(ÙZ]the color table index for white is all zeros and the color table index for black is all ones.°dONLNd¢Â<Òm*>For example, suppose your source image was a 4-bit deep color °dONLNd‡‰mó(
  5776. ãPixMap°dONLNdÊÂóÒû)*. °dONLNdËÂûÒ˛)Then the color table°dONLNd˝Ò<˝”(ZWindex for white (in binary) is 0000 and the index for black is 1111. And let’s suppose °dONLNdTÒ”˝˛(Ò    that your°dONLNd^˝<    Û(%ZXforeground color is green with an index of 1101 while your background color is red with °dONLNd∂˝Û    ˛(%an°dONLNdπ    <ë(1ZGindex of 0011. Then for the black pixels, the above procedure produces:
  5777.     °dONLNd!`,á+$;ColoredPixelValue = (NOT(1111) AND 0011) OR (1111 AND 1101)°dONLNd?+`6á*
  5778. ;     1101         = (  0000    AND 0011) OR (1111 AND 1101)
  5779. °dONLNd{A<M(iZ-And the operation on the white pixels yields:
  5780.     °dONLNd™Z`eá+$;ColoredPixelValue = (NOT(0000) AND 0011) OR (0000 AND 1101)°dONLNdÁd`oá*
  5781. ;     0011         = (  1111    AND 0011) OR (0000 AND 1101) ¡X¡
  5782. (÷ZQD 4 - Colorizing With CopyBits(÷1) of 3(ÏZM.QD.ColorizingWithCopyBitsˇ°¿Ù%%DSIDICT:_cv
  5783. currentdict /bu known {bu}if
  5784. userdict /_cv known not{userdict /_cv 30 dict put}if
  5785. _cv begin
  5786. /bdf{bind def}bind def
  5787. currentscreen/cs exch def/ca exch def/cf exch def
  5788. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  5789. /ss{//cf //ca //cs setscreen}bdf
  5790. /stg{ss setgray}bdf
  5791. /strgb{ss setrgbcolor}bdf
  5792. /stcmyk{ss cvcmyk}bdf
  5793. /min1{dup 0 eq{pop 1}if}bdf
  5794. end
  5795. currentdict /bn known {bn}if
  5796. †ø‹◊#ˇ ˇˇˇˇ#◊ 
  5797. IR,Times
  5798. .+6-Macintosh Technical Notes /4/˘
  5799. °dONLNd,ë*Possible Problems
  5800. °dONLNd8DG*AThis colorizing will only work on 2-color (i.e. black and white) °dONLNdS8GD⁄(`eimages, and then only if those°dONLNdrDPÑ(l6colors occupy the first °dONLNdäDÑP⁄)lKand last entries in the color table. Trying to colorize colors that are not°dONLNd÷P\F(x6Ethe first and last color table entries will yield unexpected results.°dONLNdhtm*LThis is mainly due to the fact that the colorizing algorithm uses a pixel’s °dONLNdhhmt⁄(êãcolor table index value°dONLNdÄtÄ(ú60rather than its actual RGB color. To illustrate °dONLNd∞tÄ⁄)˜&this, let’s assume that foreground and°dONLNd◊Äåy(®6Fbackground colors are as above, and your image contains yellow with a °dONLNdÄyå⁄(®ócolor table index of°dONLNd2åòÂ(¥6*1000. The colorizing operation would give:,
  5801. Courier
  5802.     °dONLNd^§<Øc+$;ColoredPixelValue = (NOT(1000) AND 0011) OR (1000 AND 1101)°dONLNdõÆ<πc*
  5803. ;     1011         = (  0111    AND 0011) OR (1000 AND 1101)
  5804. °dONLNd◊ƒ–ï(Ï6NSince the color table may have any RGB color at the resulting index position, °dONLNd%ƒï–⁄(Ï≥the final color°dONLNd5–‹k(¯6Fmay not even be close to the source, foreground, or background colors.°dONLNd|ËÙé*PSimilar things occur if you are trying to colorize a black and white image when °dONLNdÃËéÙ⁄(¨white and black°dONLNd‹Ù,(6>do not occupy the first and last positions in the color table.°dONLNd
  5805. ê*The bottom line rules for °dONLNd5 ê»)xCopyBits°dONLNd=
  5806. »s)8%ing in a color environment are these:°dONLNdc%*1.(MH•°dONLNde%71º)
  5807. OThou shalt set thy background color to white and thy foreground color to black °dONLNd¥%º1⁄(M⁄before°dONLNdª27>Y(ZUcalling °dONLNd√1Y=ë)"CopyBits°dONLNdÀ2ë>°)8 or °dONLNdœ1°=Ÿ)CopyMask°dONLNd◊2Ÿ>ª)8., unless thou art coloring a monochrome image.°dONLNdJ*V.(rH•°dONLNdJ7V∂)
  5808. QThou shalt, when colorizing, make sure that the first color table entry is white °dONLNdYJ∂V⁄(r‘and the°dONLNdaV7bJ(~Ulast °dONLNdgV`b◊))color table entry is black.°dONLNdÉnz.(ñ6<The second rule is easy to follow because the default color °dONLNdøn.z⁄(ñL$tables are constructed properly, and°dONLNd‰zÜv(¢6if you are using the °dONLNd˘zvÜ⁄)^KPalette Manager (and you are, right?) then it will make sure that the color°dONLNdEÜíz(Æ6tables obey this rule.
  5809. °dONLNd\™πÍ*'How To Colorize—An Example
  5810. °dONLNdw≈—ò*This code fragment shows °dONLNdê≈ò—⁄)ÄDhow to implement a color fill, like the paint bucket in MacPaint. It°dONLNd’“fiü(˙6relies on three main things: °dONLNdÚ—ü›fi)á    SeedCFill°dONLNd˚“fifih)?  for calculating the fill area, °dONLNd—h›†)äCopyMask°dONLNd#“†fi∂)8 for °dONLNd(“∂fi⁄)actually°dONLNd1fiÍÔ(6,changing the bits, and QuickDraw colorizing.
  5811.     °dONLNd^ˆ:*:PROCEDURE PaintBucket(where: Point; paintColor: RGBColor);°dONLNdö
  5812. <K+$VAR°dONLNd†`É+$
  5813. savedFG°dONLNd®®fl)H : RGBColor;°dONLNd∂`)É(E~offBits°dONLNdæ®)’)H    : BitMap;°dONLNd…2<=U(YZBEGIN°dONLNd—<`G+$
  5814. ${First, create an offscreen bitmap.}°dONLNd¯F`Q*
  5815. %offBits.bounds := myWindow^.portRect;°dONLNd P`[Ï*
  5816. WITH offBits.bounds DO BEGIN°dONLNd@ZÑeç+$
  5817. 5offBits.rowBytes := ((right - left + 15) DIV 16) * 2;°dONLNdydÑo∞*
  5818. <offBits.baseAddr := NewPtr((bottom-top) * offBits.rowBytes);°dONLNd∏n`yt(ï~END;°dONLNdøÇ`çZ*2{Check MemError here! Make sure NewPtr succeeded!} ¡4¡˘
  5819. (÷62) of 3(÷nQD 4 - Colorizing With CopyBits+M.QD.ColorizingWithCopyBitsˇ    ¨◊#ˇ ˇˇˇˇ#◊ 
  5820. IR,Times
  5821. .+Z-Developer Support Center(-Ï
  5822. March 1988 /X/,
  5823. Courier
  5824.     °dONLNdÑ(ú(D¢8SeedCFill(myWindow^.portBits,offBits,myWindow^.portRect,°dONLNd<'®2z+$
  5825. *myWindow^.portRect,where.h,where.v,NIL,0);°dONLNdi1Ñ<Ú(X¢GetForeColor(savedFG);°dONLNdÇ;ÑF*
  5826. RGBForeColor(paintColor);°dONLNdûEÑPø*
  5827. ?CopyMask(offBits,offBits,myWindow^.portBits,myWindow^.portRect,°dONLNd·O®Zk+$
  5828. 'myWindow^.portRect,myWindow^.portRect);°dONLNd YÑdÚ(Ä¢RGBForeColor(savedFG);°dONLNd$mÑx*DisposPtr(offBits.BaseAddr);°dONLNdBw`Çt(û~END;
  5829. °dONLNdGé<öÉ(∂Z
  5830. The variable °dONLNdTçÉô¥)GoffBits°dONLNd[é¥ö)1 is an offscreen °dONLNdlçô=)_BitMap°dONLNdré=öE)* °dONLNdséEöo)(not a °dONLNdzçoôô)*PixMap°dONLNdÄéôöƒ)*) with °dONLNdáçƒôÓ)+bounds°dONLNdçéÓö˛)* =°dONLNdêö<¶∫(√ZmyWindow^.portRect°dONLNd¢õ∫ß»)~.  °dONLNd•ö»¶)    SeedCFill°dONLNdÆõßy)? effectively creates, in °dONLNd«õyßø)rthe offscreen °dONLNd’öø¶È)FBitMap°dONLNd€õÈ߲)*,  a°dONLNd‡®<¥_(–Z:monochrome image of the bits that we want to paint. Since °dONLNdß_≥ê(–}offBits°dONLNd!®ê¥Ì)1 contains the exact °dONLNd5®Ì¥˛)]bits°dONLNd:µ<¡õ(›ZLthat we want to paint, it is used as both the source image and the mask for °dONLNdÜ¥õ¿”(›πCopyMask°dONLNdéµ”¡◊)8.°dONLNdêÕ<Ÿ(ıZaBy setting the foreground color to the desired paint color, the result is a colorized version of °dONLNdÒÕŸ˛(ıthe°dONLNdı⁄<Ê•(Zmask (the paint area) °dONLNd ⁄•ÊJ)ibeing copied onto the window’s °dONLNd*ŸJÂt)•PixMap°dONLNd0⁄tÊ˛)* without affecting any other°dONLNdMÊ<ÚQ(Zbits.°dONLNdS<"¶*0Further Reference: AXA°dONLNdf#N/R+
  5831. •°dONLNdh#`/¥)Color QuickDraw ¡X¡
  5832. (÷ZQD 4 - Colorizing With CopyBits(÷3) of 3(ÏZM.QD.ColorizingWithCopyBitsˇ◊#ˇ ˇˇˇˇ#◊†Ç 
  5833. /ZÅ#
  5834.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  5835. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  5836. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  5837. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  5838. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  5839.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  5840. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  5841. IR.°dONLNdn<Åh(õZ"QD 5 - Displaying Large PICT Files
  5842. °dONLNd#Ä<èá*    QuickDraw
  5843. °dONLNd.õ<ßt* Revised by:°dONLNd;õ≈߲(√„
  5844. March 1988°dONLNdFß<≥q(œZ Written by:°dONLNdRßÑ≥∑)H Rick Blair °dONLNd^ßœ≥˛(œÌ    July 1987°dONLNdhø<Àp(ÁZ>Now that we have scanners and other massive-picture producing °dONLNd¶øpÀ˛(Áétypes of applications, there is°dONLNdΔÀ<◊(ÛZ(a need to address the problem of how to °dONLNdÓÀ◊˛)…2display a PICT format object that is bigger than a°dONLNd!◊<„k(ˇZAcurrent PICT resource is allowed to be. Note that this technique °dONLNdb◊k„˛(ˇâapplies equally well to version°dONLNdÇ„<Ôñ( ZG1 and version 2 (word-opcode) pictures as produced by the Macintosh II. X
  5845. °dONLNd <#»*4Future Compatibility
  5846. °dONLNdfl0<<„*"Think of the handle returned by a ,
  5847. Courier°dONLNd/„;})ßGetResource('PICT',ID)°dONLNd0}<≈)ö as a “handle” °dONLNd&0≈<˛)H in the more°dONLNd2<<H≥(dZMgeneral sense of being an abstract “tag”—something that the ROM routines can °dONLNd<≥H˛(d—use to draw the°dONLNdèH<T¡(pZPpicture with. Don’t assume that the entire picture has been read into memory or °dONLNdflH¡T˛(pfl that you can°dONLNdÏU<a(}Z)directly read any bytes beyond the basic °dONLNdT`3)ΔPicture°dONLNdU3aç)1 record structure (°dONLNd/Tç`æ)ZpicSize°dONLNd6Uæa˛)1  followed by°dONLNdCa<mt(äZpicFrame°dONLNdKbtn°)8:). Someday we may provide a mechanism for the resource to °dONLNdÖb°n˛(äøbe disk- instead of°dONLNdôn<zø(ñZLmemory-based. The QuickDraw bottleneck procedures will know how to get data °dONLNdÂnøz˛(ñ› from and put°dONLNdÚz<Üÿ(¢Z#data into the pictures in any case.
  5848. °dONLNdû<≠Ï*'Spooling from a PICT file
  5849. °dONLNd0π<≈**In order to display pictures of arbitrary °dONLNdZπ≈˛)»1size, your application should be able to import a°dONLNdå≈<—∫(ÌZQuickDraw picture from a °dONLNd•≈∫—˛)~Afile of type PICT. This is the file produced by a “Save as…” from°dONLNdÁ—<›˝(˘Z&MacDraw with the PICT option selected.°dONLNdÈ<ı}*?What follows is a small program fragment that demonstrates how °dONLNdMÈ}ı˛(õto spool in a picture from°dONLNdhı<~(Z[the data fork °dONLNdwı~˛)BQof] a PICT file. The picture can be larger than the historical 32K resource size.°dONLNd…<>(*Z6See technical note #88 if you are unfamiliar with the °dONLNdˇ>
  5850. h(*\Signal°dONLNdh˘)* mechanism. We assume that °dONLNd ˘˛)ëa°dONLNd"<ê(7Z CatchSignals°dONLNd.ê˙)T has been done before °dONLNdD˙x)jGetandDrawPICTFile
  5851. °dONLNdVx{)~ 
  5852. °dONLNdW{•)
  5853. is called.
  5854. °dONLNdb3<BÃ(^ZMPW Pascal Example
  5855.     °dONLNdvN`YU+$1{the following variable must be at the top level}°dONLNd©b`mo*VAR°dONLNdÆl`w†*
  5856. @   globalRef   : INTEGER;      {refNum of the file to read from}°dONLNdÄ`ãZ*2{the following procedure must be at the top level} ¡X¡
  5857. (÷Z"QD 5 - Displaying Large PICT Files(÷1) of 5(ÏZM.QD.DisplayingLargePictˇ°¿Ù%%DSIDICT:_cv
  5858. currentdict /bu known {bu}if
  5859. userdict /_cv known not{userdict /_cv 30 dict put}if
  5860. _cv begin
  5861. /bdf{bind def}bind def
  5862. currentscreen/cs exch def/ca exch def/cf exch def
  5863. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  5864. /ss{//cf //ca //cs setscreen}bdf
  5865. /stg{ss setgray}bdf
  5866. /strgb{ss setrgbcolor}bdf
  5867. /stcmyk{ss cvcmyk}bdf
  5868. /min1{dup 0 eq{pop 1}if}bdf
  5869. end
  5870. currentdict /bn known {bn}if
  5871. †ø
  5872. Ë◊#ˇ ˇˇˇˇ#◊ 
  5873. IR,Times
  5874. .+6-Macintosh Technical Notes /4/˘,
  5875. Courier
  5876.     °dONLNd<(T+$8PROCEDURE GetPICTData(dataPtr: Ptr; byteCount: INTEGER);°dONLNd:'<26*
  5877. 2{replacement for the QuickDraw bottleneck routine}°dONLNdn;<FZ*   VAR°dONLNdvE<Pæ*
  5878.       err         : OSErr;°dONLNdíO<Z»*
  5879.       longCount   : LONGINT;°dONLNd∞c<nd*   BEGIN°dONLNd∫m<xÕ*
  5880.       longCount := byteCount;°dONLNdŸw<Ç1*
  5881. 1      err := FSRead(globalRef,longCount,dataPtr);°dONLNd Å<åü*
  5882. G      {can't check for an error because we don't know how to handle it}°dONLNdUã<ñ_*
  5883.    END;°dONLNd^ü<™U*CONST°dONLNde©<¥Ü*
  5884. B   abortPICT    = 128;         {error code if DrawPicture aborted}°dONLNd©Ω<»©*IPROCEDURE GetDrawPICTFile;     {read in a PICT FILE selected by the user}°dONLNdÙ—<‹Z*   VAR°dONLNd¸€<ÊT*
  5885. 8      wher        : Point;     {where to display dialog}°dONLNd6Â<*
  5886. -      reply       : SFReply;   {reply record}°dONLNdeÔ<˙h*
  5887. <      myFileTypes : SFTypeList; {more Standard FILE goodies}°dONLNd£˘<»*
  5888.       numFileTypes: INTEGER;°dONLNd¡
  5889. <◊*      savedProcs  : QDProcsPtr;°dONLNd‚<"|*
  5890. @      myProcs     : QDProcs;   {use CQDProcs for a color window}°dONLNd$+<6©*I      myPicture   : PicHandle; {we need a picture handle for DrawPicture}°dONLNdo5<@»*
  5891.       longCount   : LONGINT;°dONLNdç?<J»*
  5892.       myEOF       : LONGINT;°dONLNd´I<T»*
  5893.       myFilePos   : LONGINT;°dONLNd…]<hd*   BEGIN°dONLNd”g<rõ*
  5894.       wher.h := 20;°dONLNdËq<|õ*
  5895.       wher.v := 20;°dONLNd˝{<Ü;*
  5896. 3      numFileTypes := 1;       {display PICT files}°dONLNd2Ö<ê◊*
  5897.       myFileTypes[0] := 'PICT';°dONLNdSè<ö|*
  5898. @      SFGetFile(wher,'',NIL,numFileTypes,myFileTypes,NIL,reply);°dONLNdï£<Æ“*      IF reply.good THEN BEGIN°dONLNdµ≠<∏Å*
  5899. A         SetStdProcs(myProcs); {use SetStdCProcs for a CGrafPort}°dONLNd¯∑<¬*
  5900. ,         myProcs.getPicProc := @GetPICTData;°dONLNd&¡<Ãö*
  5901. F         savedProcs := thePort^.grafProcs; {set the grafProcs to ours}°dONLNdnÀ<÷*
  5902. (         thePort^.grafProcs := @myProcs;°dONLNdòfl<Ír*>         myPicture := PicHandle(NewHandle(SizeOf(myPicture)));°dONLNdÿÛ<˛m*=         Signal(FSOpen(reply.fname,reply.vRefNum,globalRef));°dONLNd˝<ã*
  5903. C         Signal(GetEOF(globalRef,myEOF)); {get EOF for later check}°dONLNd\<Ü*
  5904. B         Signal(SetFPos(globalRef,fsFromStart,512)); {skip header}°dONLNd†<&h*<         {read in the (obsolete) size word and the picFrame}°dONLNdfi%<0*
  5905. (         longCount := SizeOf(myPicture);°dONLNd/<:m*
  5906. =         Signal(FSRead(globalRef,longCount,Ptr(myPicture^)));°dONLNdGC<N§*H         DrawPicture(myPicture,myPicture^^.picFrame); {draw the picture}°dONLNdëW<bï*E         Signal(GetFPos(globalRef,filePos)); {get position for check}°dONLNdÿa<l*
  5907. $         Signal(FSClose(globalRef));°dONLNd˛u<Ä    *)         DisposHandle(Handle(myPicture));°dONLNd)â<îr*>         thePort^.grafProcs := savedProcs; {restore the procs} ¡4¡˘
  5908. (÷62) of 5(÷d"QD 5 - Displaying Large PICT Files+%M.QD.DisplayingLargePictˇ»◊#ˇ ˇˇˇˇ#◊ 
  5909. IR,Times
  5910. .+Z-Developer Support Center(-Ê October 1990 /X/,
  5911. Courier
  5912.     °dONLNd'`2}(N~9         {Check for errors. If there wasn't enough room,}°dONLNd;1`<}*
  5913. 9         {DrawPicture will abort; the FILE position mark}°dONLNdv;`F7*
  5914. +         {won't be at the end of the FILE.}°dONLNd£E`Pd*
  5915. 4         IF filePos <> myEOF THEN Signal(abortPICT);°dONLNdŸO`Z‚*
  5916.       END; {IF reply.good}°dONLNdıY`d›*
  5917.    END; {GetDrawPICTFile}
  5918. °dONLNd{<ä≠(¶Z
  5919. MPW C Example
  5920.     °dONLNdñ<°@*4/*replacement for the QuickDraw bottleneck routine*/°dONLNdR†<´*
  5921. *pascal void GetPICTData(dataPtr,byteCount)°dONLNd}™<µK*
  5922. Ptr°dONLNdÉ™®µ–)ldataPtr;°dONLNdç¥<øU(€Zshort°dONLNd葉ø⁄)l
  5923. byteCount;°dONLNd†“<›õ(˘Z{ /* GetPICTData */°dONLNdµ‹`Áy+$
  5924. OSErr°dONLNdΩ‹ÃÁ‡)lerr;°dONLNd√Ê`Òt(
  5925. ~long°dONLNd ÊÃÒ˛)l
  5926. longCount;°dONLNd÷˙`Œ(!~longCount = byteCount;°dONLNdÓ`7*
  5927. +err = FSRead(globalRef,&longCount,dataPtr);°dONLNd`Ø*
  5928. C/*can't check for an error because we don't know how to handle it*/°dONLNd_<#õ(?Z} /* GetPICTData */°dONLNds,<7ı*%/*error code if DrawPicture aborted*/°dONLNdô6<A_*
  5929. #define°dONLNd°6ÑAË)H   abortPICT     128°dONLNdøJ<UØ(qZOSErr GetDrawPICTFile()°dONLNdÿJUÃ)¥,/*read in a PICT FILE selected by the user*/°dONLNd^<iA(ÖZ{°dONLNd^`i…)$/* GetDrawPICTFile */°dONLNd!r`}~*Point °dONLNd)r®}Δ)Hwher; °dONLNd1r}w)H/*where to display dialog*/°dONLNdN|`áÉ(£~SFReply°dONLNdV|®á–)Hreply;  °dONLNd_|á@)H/*reply record*/°dONLNdqÜ`ëí(≠~
  5930. SFTypeList°dONLNd|Ü®ë‰)H myFileTypes;°dONLNdâÜëÜ)H/*more Standard FILE goodies*/°dONLNd©ê`õ~(∑~short °dONLNd±ê®õÈ)H
  5931. numFileTypes;°dONLNd¿ö`•y(¡~OSErr°dONLNd«ö®•º)Herr;°dONLNdÕ§`Øí(À~
  5932. QDProcsPtr°dONLNdÿ§®Øfl)H savedProcs;°dONLNdÂÆ`πÉ(’~QDProcs°dONLNdÌÆ®π–)HmyProcs;°dONLNdˆÆπü)H#/*use CQDProcs for a color window*/°dONLNd∏`√ç(fl~    PicHandle°dONLNd%∏®√⁄)H
  5933. myPicture;°dONLNd0∏√Ã)H,/*we need a picture handle for DrawPicture*/°dONLNd^¬`Õt(È~long°dONLNdd¬®Õ )HlongCount,myEOF,filePos;°dONLNd~÷`·∫(˝~      wher.h = 20;°dONLNdí‡`Î∫*
  5934.       wher.v = 20;°dONLNd¶Í`ıˆ*
  5935.       numFileTypes = 1;       °dONLNd«Í\ı )¸/*display PICT files*/°dONLNdflÙ`ˇˆ(~      myFileTypes[0] = 'PICT';°dONLNdˇ˛`    •*
  5936. A      SFGetFile(wher,'',nil,numFileTypes,myFileTypes,nil,&reply);°dONLNdB`…*      if (reply.good)°dONLNd\Ñ'â+$
  5937. {°dONLNda&®1+$
  5938. SetStdProcs(&myProcs);°dONLNd{0®;\*
  5939. $/*use SetStdCProcs for a CGrafPort*/°dONLNd°:`Eç(a~             °dONLNd´:®EM)H!myProcs.getPicProc = GetPICTData;°dONLNdŒD`Oç(k~             °dONLNdÿD®Oa)H%savedProcs = (*qd.thePort).grafProcs;°dONLNdX®c9*/*set the grafProcs to ours*/°dONLNd b`mç(â~             °dONLNd*b®mW)H#(*qd.thePort).grafProcs = &myProcs;°dONLNdOv`Åç(ù~             °dONLNdYv®Å¢)H2myPicture = (PicHandle)NewHandle(sizeof(Picture)); ¡X¡
  5940. (÷Z"QD 5 - Displaying Large PICT Files(÷3) of 5(ÏZM.QD.DisplayingLargePictˇ@◊#ˇ ˇˇˇˇ#◊ 
  5941. IR,Times
  5942. .+6-Macintosh Technical Notes /4/˘,
  5943. Courier
  5944.     °dONLNdÑ(à+l4err = FSOpen(&reply.fName,reply.vRefNum,&globalRef);°dONLNd8'Ñ2*
  5945. if (err != noErr) return err;°dONLNdW;<FU(bZ     °dONLNd];`Fe)$ °dONLNd_;ÑF)$err = GetEOF(globalRef,&myEOF);°dONLNdÇEÑP *
  5946. /*get EOF for later check*/°dONLNd°OÑZ*
  5947. if (err != noErr) return err;°dONLNd¬cÑnú*8err = SetFPos(globalRef,fsFromStart,512);/*skip header*/°dONLNd¸m<xi(îZ             °dONLNdmÑx)Hif (err != noErr) return err;°dONLNd%Å<åi(®Z             °dONLNd/ÅÑåç)H5/*read in the (obsolete) size word and the picFrame*/°dONLNdfã<ñi(≤Z             °dONLNdpãÑñ)HlongCount = sizeof(Picture);°dONLNdéï<†d(ºZ        °dONLNdóïцà)H4 err = FSRead(globalRef,&longCount,(Ptr)*myPicture);°dONLNdÕü<™i(ΔZ             °dONLNd◊üÑ™)Hif (err != noErr) return err;°dONLNdˆ≥<æi(⁄Z             °dONLNd≥Ñæó)H7DrawPicture(myPicture,&(**myPicture).picFrame); /*draw °dONLNd?Ω»U+ê
  5948.  
  5949. the picture*/°dONLNdP—Ñ‹ç(¯¢5err = GetFPos(globalRef,&filePos);/*get position for °dONLNdç€Ê7+ê
  5950. check*/°dONLNdñÂ<i( Z             °dONLNd†ÂÑ)Hif (err != noErr) return err;°dONLNdøÔ<˙i(Z             °dONLNd…ÔÑ˙)Herr = FSClose(globalRef);°dONLNd‰˘<i( Z             °dONLNdÓ˘Ñ)Hif (err != noErr) return err;°dONLNd
  5951. 
  5952. <i(4Z             °dONLNd
  5953. Ñ$)H DisposHandle((Handle)myPicture);°dONLNd9!<,i(HZ             °dONLNdC!Ñ,É)H3(*qd.thePort).grafProcs = savedProcs;/*restore the °dONLNd~+67+ê
  5954. procs*/°dONLNdá?<Jd(fZ        °dONLNdê?ÑJÉ)H3 /*Check for errors. if there wasn't enough room,*/°dONLNd≈I<Td(pZ        °dONLNdŒIÑTÉ)H3 /*DrawPicture will abort; the FILE position mark*/°dONLNdS<^i(zZ             °dONLNd
  5955. SÑ^8)H$/*won't be at the end of the FILE.*/°dONLNd5gÑrL*(if (filePos != myEOF)  return abortPICT;°dONLNdaqÑ|fi*
  5956. else return noErr;°dONLNdu{<Ü»(¢Z      } /*if (reply.good) */°dONLNdíÖê"(¨6} °dONLNdïÖ<ê•)$/* GetDrawPICTFile */
  5957. °dONLNd´ß∂Â(“6More on Picture Compatibility
  5958. °dONLNd…¬Œô*Many applications already °dONLNd„¬ôŒ⁄)Å:support PICT resources larger than 32K. The 128K ROMs (and°dONLNdŒ⁄‰(ˆ6)later) allow pictures as large as memory °dONLNdGŒ‰⁄⁄)Ã-(or spooling) will accommodate. This was made°dONLNdu⁄ÊŒ(6$possible by having QuickDraw ignore °dONLNdô⁄ŒÊ÷)∂7the size word and simply read the picture until the end°dONLNd–⁄÷Ê⁄(Ù-°dONLNd—ÊÚ¨(6of-picture opcode was reached.°dONLNd˛
  5959. √*WFor maximum safety and convenience, let QuickDraw generate and interpret your pictures.°dONLNdH"á*MWhile Apple has provided you with the data formats that allow you to read or °dONLNdïá"⁄(>•write picture data°dONLNd®".ˆ(J6+directly, we recommend that you always let °dONLNd”"ˆ.⁄)fi+DrawPicture or OpenPicture and ClosePicture°dONLNdˇ.:{(V6process the opcodes.°dONLNdFRª*YOne reason to read a picture directly by scanning the opcodes would be to disassemble it °dONLNdmFªR⁄(nŸto, for°dONLNduR^s(z6example, extract a °dONLNdàRs^⁄)[GColor QuickDraw pixel map to save off in a private data structure. This°dONLNd–^jµ(Ü6 shouldn’t normally be necessary.°dONLNdÒvǬ*&If you do look at the picture data be °dONLNdv¬Ç⁄)™7sure and check the version information. You may want to°dONLNdOÇé˘(™63put up an alert in your application that indicates °dONLNdÇǢé⁄)·.to the user when a picture was created using a ¡4¡˘
  5960. (÷64) of 5(÷d"QD 5 - Displaying Large PICT Files+%M.QD.DisplayingLargePictˇ◊#ˇ ˇˇˇˇ#◊ 
  5961. IR,Times
  5962. .+Z-Developer Support Center(-Ê October 1990 /X/
  5963. °dONLNd<)Ì(EZXlater version of the picture format than your application recognizes, letting them know °dONLNdXÌ)˛(E that°dONLNd])<5…(QZMsome elements of the picture cannot be displayed. If the version information °dONLNd™)…5˛(QÁ indicates a°dONLNd∂5<AŸ(]Z QuickDraw picture version later °dONLNd÷5ŸA˛)ù9than the one recognized by your application, your program°dONLNdA<M∞(iZMshould skip over the new opcodes and only attempt to parse the ones it knows.°dONLNd^Y<e-*5As with reading picture data directly, it is best to °dONLNdìY-e˛)Ò(use QuickDraw to create data in the PICT°dONLNdºe<qS(çZ<format. If you do need to create PICT format data directly, °dONLNd¯eSq˛(çq'it is essential that you use the latest°dONLNd q<}Â(ôZWopcode specifications and that you thoroughly test the data produced on both color and °dONLNdwqÂ}˛(ôblack°dONLNd}}<âí(•ZDand white Macintosh machines. Contact Macintosh Developer Technical °dONLNd¡}íâ˛(•∞Support if you are not°dONLNdÿâ<ï(±Z-sure that you have the latest specifications.°dONLNd°<≠·*UApple does not guarantee that a picture which wasn’t produced by QuickDraw will work.°dONLNd\—<›¶*0Further Reference: ¸X¸°dONLNdofiNÍR+
  5964. •°dONLNdqfi`Íñ)    QuickDraw°dONLNd{ÍNˆR(l•°dONLNd}Í`ˆ#)$Technical Note M.IM.PictureOpcodes —°dONLNd§ˆÑÒ+$ Internal Picture Format°dONLNdºNR(*l•°dONLNdæ`¸)Technical Note M.PT.Signals —°dONLNdfiÑß+$ Signals ¡X¡
  5965. (÷Z"QD 5 - Displaying Large PICT Files(÷5) of 5(ÏZM.QD.DisplayingLargePictˇF◊#ˇ ˇˇˇˇ#◊†Ç 
  5966. /ZÅ#
  5967.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  5968. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  5969. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  5970. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  5971. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  5972.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  5973. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  5974. IR.°dONLNdn<Åx(õZQD 6 °dONLNdnxŞ)<*- Every Picture [Comment] Tells Its Story,°dONLNd0Ä<ìá(≠Z    Don’t It?
  5975. °dONLNd:í<°á*    QuickDraw
  5976. °dONLNdE≠<πt* Revised by:°dONLNdR≠¬π˛(’‡  March 1988°dONLNd^π<≈q(·Z Written by:°dONLNdjπÑ≈¥)H
  5977. Rick Blair°dONLNduπ±≈˛(·œ
  5978. November 1987°dONLNdÉ—<›»(˘ZApplication-specific picture °dONLNd†—»›˛)å:comment conflict and registration is addressed, along with°dONLNd€›<È8(Z4Developer Technical Support’s method for solving it. X°dONLNd<◊*%"I will assume that the nature and °dONLNd2◊˛)õ:usefulness of picture comments are already well known. The°dONLNdm<‰(6Z$problem I am addressing is that, as °dONLNd뉲)®:it stands, developers must register their comments with us°dONLNdÃ<&π(BZL(Developer Technical Support) or run the risk of using the same comments as °dONLNdπ&˛(B◊
  5979. those used by°dONLNd&&<2 (NZ,Apple or within another third party product.°dONLNdS><JD*2The idea here is to provide a “metacomment” which °dONLNdÖ>DJ˛(fb$will contain information about which°dONLNd™J<VX(rZ;application owns the comment as well as the comment itself:,
  5980. Courier
  5981.     °dONLNdÊb<m·*!ApplicationComment (long comment)°dONLNdbmh)¥kind = 100  size = n + 6°dONLNd"l`w•(ì~Adata = application signature (i.e. 'MPNT' for MacPaint) = 4 bytes°dONLNdev`Å-*
  5982. )       application “local” kind = 2 bytes°dONLNdêÄ`ãÒ*
  5983.        comment data = n bytes
  5984. °dONLNdÆñ<¢◊(æZIn this way each comment may °dONLNdÀñ◊¢˛)õ?be specific to an application. It is still up to a developer to°dONLNd ¢<Æ-( Z1publish information about the comments they have °dONLNd<¢-Æ˛)Ò*defined if they wish them to be understood°dONLNdgÆ<∫ƒ(÷Zand used by other programs.°dONLNdÉΔ<“É*FPreviously assigned and registered comments will still be valid. This °dONLNd…ΔÉ“˛(Ó°means that those  defined°dONLNd„“<fi≥(˙ZOfor the LaserWriter or MacDraw, for instance, will retain their normal meaning.°dONLNd3Í<ˆË*$Suppose your application (creator = 
  5985. °dONLNdWÍˈ)¨'MYAP')
  5986. °dONLNd^͈˛)*. wanted to define a comment. The appearance of°dONLNdçˆ<N(Zthe °dONLNdëˆN˛)Rcomment would be as follows (assuming you chose 128 to be the “local” kind for the°dONLNd‰<n(*Z    comment):
  5987.     °dONLNdÔ`%π+$Ekind = 100; data = 'MYAP' [4 bytes] + 128 [2 bytes] + additional data
  5988. °dONLNd5H<T¶(pZFurther Reference: sXs°dONLNdHUNaR+
  5989. •°dONLNdJU`añ)    QuickDraw°dONLNdTaNmR(âl•°dONLNdVa`m)"Technical Note M.IM.PictComments —°dONLNd|mÑyx+$ /Optimizing for the LaserWriter—Picture Comments ¡X¡
  5990. (÷Z9QD 6 - Every Picture [Comment] Tells Its Story, Don’t It?(÷1) of 1(ÏZM.QD.EveryPictureCommentˇ°¿Ù%%DSIDICT:_cv
  5991. currentdict /bu known {bu}if
  5992. userdict /_cv known not{userdict /_cv 30 dict put}if
  5993. _cv begin
  5994. /bdf{bind def}bind def
  5995. currentscreen/cs exch def/ca exch def/cf exch def
  5996. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  5997. /ss{//cf //ca //cs setscreen}bdf
  5998. /stg{ss setgray}bdf
  5999. /strgb{ss setrgbcolor}bdf
  6000. /stcmyk{ss cvcmyk}bdf
  6001. /min1{dup 0 eq{pop 1}if}bdf
  6002. end
  6003. currentdict /bn known {bn}if
  6004. †ø™◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  6005. /ZÅ#
  6006.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6007. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6008. .eRSeRS+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6009. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6010. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6011.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6012. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  6013. IR.°dONLNdo<Ç(úZQD 7 - Off-Screen Bitmaps
  6014. °dONLNdÅ<êá*    QuickDraw
  6015. °dONLNd%ú<®t* Revised by:°dONLNd1úÑ®)HJon Zap & Forrest Tanaka°dONLNdJúÕ®˛(ƒΠ   June 1990°dONLNdT®<¥q(–Z Written by:°dONLNd`®Ñ¥))H!Jim Friedlander & Ginger Jernigan°dONLNdÇ®œ¥˛(–Ì    July 1985°dONLNdå¿<Ãû(ËZThis Technical Note °dONLNd†¿ûÃ˛)bHprovides an example of creating an off-screen bitmap, drawing to it, and°dONLNdÈÃ<ÿfi(ÙZ#then copying from it to the screen.°dONLNd
  6016. ÿ<‰ÿ* Changes since April 1990:°dONLNd&ÿÿ‰#)ú  Clarified the °dONLNd6ÿ#‰˛)K)section on window updates with off-screen°dONLNd`‰<e( Z>bitmaps to explicitly limit these updates to your own windows. X°dONLNdü    <*%(The following is an example of creating °dONLNd«    ˛)≈1and drawing to an off-screen bitmap, then copying°dONLNd˘<!”(=ZQfrom it to an on-screen window.  We supply this example in both MPW Pascal and C.°dONLNdK-<9É*
  6017. MPW Pascal°dONLNdVE<Q*'First, let’s look at a general purpose °dONLNd}EQ˛)¥7function to create an off-screen bitmap.  This function°dONLNdµR<^t(zZ creates the ,
  6018. Courier°dONLNd¡Qt]¨)8GrafPort°dONLNd…R¨^Ù)8 on the heap. °dONLNd◊RÙ^˛)H3 You could also create it on the stack and pass the°dONLNd ^<j:(ÜZ:uninitialized structure to a function similar to this one.
  6019.     °dONLNdFv<Å÷*RFUNCTION CreateOffscreenBitMap(VAR newOffscreen:GrafPtr; inBounds:Rect) : BOOLEAN;°dONLNdôä<ïK*VAR°dONLNdùî<ü™*
  6020.   savePort  : GrafPtr;°dONLNd¥û<©™*
  6021.   newPort   : GrafPtr;°dONLNdÀ≤<ΩU*BEGIN°dONLNd—º<«‡*
  6022. T  GetPort(savePort);        {need this to restore thePort after OpenPort changes it}°dONLNd&–<€Æ*J  newPort := GrafPtr(NewPtr(sizeof(GrafPort)));    {allocate the GrafPort}°dONLNdq⁄<·*
  6023. !  IF MemError <> noErr THEN BEGIN°dONLNdì‰<ÔÆ*
  6024. J    CreateOffscreenBitMap := false;                {failed to allocate it}°dONLNdfiÓ<˘‹*
  6025.      EXIT(CreateOffscreenBitMap);°dONLNdˇ¯<Z*
  6026.   END;°dONLNd<
  6027. K*
  6028.   {°dONLNd
  6029.  <*
  6030. ,  the OpenPort call does the following . . .°dONLNd8<!«*
  6031. O    allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide°dONLNdâ <+i*
  6032.         open)°dONLNdì*<5◊*
  6033.     sets portBits to screenBits°dONLNd≥4<?˙*
  6034. &    sets portRect to screenBits.bounds°dONLNd⁄><I√*
  6035.     etc. (see IM I-163,164)°dONLNdˆH<S*
  6036. *    side effect: does a SetPort(offScreen)°dONLNd!R<]K*
  6037.   }°dONLNd%\<g†*
  6038.   OpenPort(newPort);°dONLNd:f<qã*
  6039. C  {make bitmap exactly the size of the bounds that caller supplied}°dONLNd~p<{ü*
  6040. G  WITH newPort^ DO BEGIN {portRect, clipRgn, and visRgn are in newPort}°dONLNdΔz<Öπ*
  6041.     portRect := inBounds;°dONLNd‡Ñ<è∏*
  6042. L    RectRgn(clipRgn, inBounds);        {avoid wide-open clipRgn, to be safe} ¡X¡
  6043. *+QD 7 - Off-Screen Bitmaps(÷1) of 6(ÏZM.QD.OffscreenBitMapsˇ°¿Ù%%DSIDICT:_cv
  6044. currentdict /bu known {bu}if
  6045. userdict /_cv known not{userdict /_cv 30 dict put}if
  6046. _cv begin
  6047. /bdf{bind def}bind def
  6048. currentscreen/cs exch def/ca exch def/cf exch def
  6049. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6050. /ss{//cf //ca //cs setscreen}bdf
  6051. /stg{ss setgray}bdf
  6052. /strgb{ss setrgbcolor}bdf
  6053. /stcmyk{ss cvcmyk}bdf
  6054. /min1{dup 0 eq{pop 1}if}bdf
  6055. end
  6056. currentdict /bn known {bn}if
  6057. †ø¶◊#ˇ ˇˇˇˇ#◊ 
  6058. IR,Times
  6059. .+6-Macintosh Technical Notes /4/˘,
  6060. Courier
  6061.     °dONLNd(î*L    RectRgn(visRgn, inBounds);         {in case inBounds is > screen bounds}°dONLNdM'26*
  6062.   END;°dONLNdT;Fô*M  WITH newPort^.portBits DO BEGIN       {baseAddr, rowBytes and bounds are in°dONLNd¢EPJ*
  6063.  
  6064.   newPort}°dONLNd≠OZã*
  6065.     bounds := inBounds;°dONLNd≈Ydî*
  6066. L    {rowBytes is size of row  It must be rounded up to even number of bytes}°dONLNdcng*
  6067. C    rowBytes := ((inBounds.right - inBounds.left + 15) DIV 16) * 2;°dONLNdVwÇD*<    {number of bytes in BitMap is rowBytes * number of rows}°dONLNdìÅå≤*
  6068. R    {see note at end of Technical Note about using _NewHandle rather than _NewPtr}°dONLNdÊãñè*
  6069. K    baseAddr := NewPtr(rowBytes * LONGINT(inBounds.bottom - inBounds.top));°dONLNd2ï†6*
  6070.   END;°dONLNd9ü™ô*
  6071. M  IF MemError <> noErr THEN BEGIN    {see if we had enough room for the bits}°dONLNdá©¥Ü*
  6072.     SetPort(savePort);°dONLNdû≥æl*
  6073. D    ClosePort(newPort);              { dump the visRgn and clipRgn }°dONLNd„Ω»5*
  6074. 9    DisposPtr(Ptr(newPort));         { dump the GrafPort}°dONLNd«“«*
  6075. #    CreateOffscreenBitMap := false;°dONLNdA—‹1*
  6076.   END°dONLNdG€ÊT*
  6077.   ELSE BEGIN°dONLNdTÂÄ*
  6078. H    { since the bits are just memory, let's erase them before we start }°dONLNdùÔ˙q*
  6079. E    EraseRect(inBounds);            {OpenPort did a SetPort(newPort)}°dONLNd„˘§*
  6080.     newOffscreen := newPort;°dONLNdÜ*
  6081.     SetPort(savePort);°dONLNd
  6082. ¬*
  6083. "    CreateOffscreenBitMap := true;°dONLNd:"6*
  6084.   END;°dONLNdA!,,*
  6085. END;
  6086. °dONLNdF7C∏*ZHere is the procedure to get rid of an off-screen bitmap created by the previous function:
  6087.     °dONLNd°OZ5*9PROCEDURE DestroyOffscreenBitMap(oldOffscreen : GrafPtr);°dONLNd€Yd1*
  6088. BEGIN°dONLNd·cn®*
  6089. P  ClosePort(oldOffscreen);                       { dump the visRgn and clipRgn }°dONLNd2mxb*
  6090. B  DisposPtr(oldOffscreen^.portBits.baseAddr);    { dump the bits }°dONLNduwÇb*
  6091. B  DisposPtr(Ptr(oldOffscreen));                  { dump the port }°dONLNd∏Åå,*
  6092. END;
  6093. °dONLNdΩó£è*HNow that you know how to create and destroy an off-screen bitmap, let’s °dONLNdóè£⁄(ø≠go through the°dONLNd§∞^(Ã6Dmotions of using one.  First, let’s define a few things to make the °dONLNdX£^ا(Ã|
  6094. _NewWindow°dONLNdb§§∞º)F call °dONLNdh§º∞⁄)a little°dONLNdq∞º;(ÿ6clearer.
  6095.     °dONLNdz»”1*CONST°dONLNdÄ“›Ü*
  6096.   kIsVisible   = true;°dONLNdó‹Áã*
  6097.   kNoGoAway    = false;°dONLNdØÊÒê*
  6098.   kMakeFrontWindow = -1;°dONLNd»˚*
  6099. 0  myString     = 'The EYE';  {string to display}
  6100. °dONLNd˘±*!Here’s the body of the test code:
  6101.     °dONLNd)'*VAR°dONLNd(3
  6102. *
  6103. 1  offscreen : GrafPtr;    {our off-screen bitmap}°dONLNdQ2=*
  6104. 4  ovalRect  : Rect;       {used for example drawing}°dONLNdÜ<G*
  6105. /  myWBounds : Rect;       {for creating window}°dONLNd∂FQq*
  6106. E  OSRect    : Rect;       {portRect and bounds for off-screen bitmap}°dONLNd¸P[ê*
  6107.   myWindow  : WindowPtr;°dONLNddo1*BEGIN°dONLNdnyb*
  6108. B  InitToolbox;                       {exercise left to the reader}°dONLNd^ÇçD*<  myWBounds := screenBits.bounds;    { size of main screen }°dONLNdõåó?*
  6109. ;  InsetRect(myWBounds, 50,50);       { make it fit better } ¡4¡˘
  6110. *#2) of 6(÷ãQD 7 - Off-Screen Bitmaps+    M.QD.OffscreenBitMapsˇ™◊#ˇ ˇˇˇˇ#◊ 
  6111. IR,Times
  6112. .+Z-Developer Support Center(-Û    June 1990 /X/,
  6113. Courier
  6114.     °dONLNd<(Ü(DZB  myWindow := NewWindow(NIL, myWBounds, 'Test Window', kIsVisible,°dONLNdC'<2÷*
  6115. R                        noGrowDocProc, WindowPtr(kMakeFrontWindow), kNoGoAway, 0);°dONLNdñ;<Fü*G  IF NOT CreateOffscreenBitMap(offscreen,myWindow^.portRect) THEN BEGIN°dONLNdflE<Pá*
  6116.     SysBeep(1);°dONLNdÔO<Zå*
  6117.     ExitToShell;°dONLNdY<dZ*
  6118.   END;°dONLNdm<x"*.  { Example drawing to our off-screen bitmap }°dONLNd6w<Ç•*
  6119.   SetPort(offscreen);°dONLNdLÅ<åÃ*
  6120. P  OSRect := offscreen^.portRect;    { offscreen bitmap's local coordinate rect }°dONLNdùã<ñ•*
  6121.   ovalRect := OSRect;°dONLNd≥ï<†»*
  6122.   FillOval(ovalRect, black);°dONLNd–ü<™Õ*
  6123.   InsetRect(ovalRect, 1, 20);°dONLNdÓ©<¥»*
  6124.   FillOval(ovalRect, white);°dONLNd ≥<æÕ*
  6125.   InsetRect(ovalRect, 40, 1);°dONLNd)Ω<»»*
  6126.   FillOval(ovalRect, black);°dONLNdF«<“ñ*
  6127.   WITH ovalRect DO°dONLNdY—<‹∏*
  6128. L    MoveTo((left+right-StringWidth(myString)) DIV 2, (top+bottom-12) DIV 2);°dONLNd¶€<Êõ*
  6129.   TextMode(srcXor);°dONLNd∫Â<Ø*
  6130.   DrawString(myString);°dONLNd“˘<«*O  { copy from the off-screen bitmap to the on-screen window.  Note that in this°dONLNd"<∏*
  6131. L  case the source and destination rects are the same size and both cover the°dONLNdo
  6132. <≥*
  6133. K  entire area.  These rects are allowed to be portions of the source and/or°dONLNdª<"—*
  6134. Q  destination and do not have to be the same size.  If they are not the same size°dONLNd
  6135. !<,*
  6136. -  then _CopyBits scales the image accordingly°dONLNd;+<6K*
  6137.   }°dONLNd?5<@†*
  6138.   SetPort(myWindow);°dONLNdT?<J;*
  6139. 3  CopyBits(offscreen^.portBits, myWindow^.portBits,°dONLNdàI<TÜ*
  6140. B           offscreen^.portRect, myWindow^.portRect, srcCopy, NIL);°dONLNdÀ]<hm*=  DestroyOffscreenBitMap(offscreen);    {remove the evidence}°dONLNd    q<|«*O  WHILE NOT Button DO;                  {give user a chance to see the results}°dONLNdY{<ÜP*
  6141. END.
  6142. °dONLNd^ë<ùh*MPW C°dONLNdd©<µ*'First, let’s look at a general purpose °dONLNdã©µ˛)¥7function to create an off-screen bitmap.  This function°dONLNd√∂<¬t(fiZ creates the °dONLNdœµt¡¨)8GrafPort°dONLNd◊∂¨¬Ù)8 on the heap. °dONLNdÂ∂Ù¬˛)H3 You could also create it on the stack and pass the°dONLNd¬<Œ:(ÍZ:uninitialized structure to a function similar to this one.
  6143.     °dONLNdT⁄<Âê*DBoolean CreateOffscreenBitMap(GrafPtr *newOffscreen, Rect *inBounds)°dONLNdô‰<ÔA*
  6144. {°dONLNdõÓ<˘õ*
  6145.   GrafPtr savePort;°dONLNdد<ñ*
  6146.   GrafPtr newPort;°dONLNd¬ <Æ*J  GetPort(&savePort);    /* need this to restore thePort after OpenPort */°dONLNd
  6147.  <+¬*N  newPort = (GrafPtr) NewPtr(sizeof(GrafPort));    /* allocate the grafPort */°dONLNd\*<5æ*
  6148.   if (MemError() != noErr)°dONLNdw4<?¬*
  6149. N    return false;                 /* failed to allocate the off-screen port */°dONLNdΔ><IP*
  6150.   /*°dONLNdÀH<S'*
  6151. /  the call to OpenPort does the following . . .°dONLNd¸R<]«*
  6152. O    allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide°dONLNdL\<gi*
  6153.         open)°dONLNdVf<q◊*
  6154.     sets portBits to screenBits°dONLNdvp<{˙*
  6155. &    sets portRect to screenBits.bounds°dONLNdùz<Ö√*
  6156.     etc. (see IM I-163,164)°dONLNdπÑ<è*
  6157. +    side effect: does a SetPort(&offScreen) ¡X¡
  6158. *+QD 7 - Off-Screen Bitmaps(÷3) of 6(ÏZM.QD.OffscreenBitMapsˇ ◊#ˇ ˇˇˇˇ#◊ 
  6159. IR,Times
  6160. .+6-Macintosh Technical Notes /4/˘,
  6161. Courier
  6162.     °dONLNd(,*  */°dONLNd'2|*
  6163.   OpenPort(newPort);°dONLNd1<S*
  6164. ?  /* make bitmap the size of the bounds that caller supplied */°dONLNdZ;F∏*
  6165.    newPort->portRect = *inBounds;°dONLNd{EP€*
  6166. '  newPort->portBits.bounds = *inBounds;°dONLNd£OZº*
  6167. T  RectRgn(newPort->clipRgn, inBounds);    /* avoid wide-open clipRgn, to be safe  */°dONLNd¯Ydº*
  6168. T  RectRgn(newPort->visRgn, inBounds);     /* in case newBounds is > screen bounds */°dONLNdMmx≠*Q  /* rowBytes is size of row, it must be rounded up to an even number of bytes */°dONLNdüwÇ∑*
  6169. S  newPort->portBits.rowBytes = ((inBounds->right - inBounds->left + 15) >> 4) << 1;°dONLNdÛãñN*>  /* number of bytes in BitMap is rowBytes * number of rows */°dONLNd2ï†≤*
  6170. R  /* see notes at end of Technical Note about using _NewHandle rather than _NewPtr°dONLNdÖü™;*
  6171.      */°dONLNdç©¥Æ*
  6172.   newPort->portBits.baseAddr =°dONLNd¨≥æ∑*
  6173. S           NewPtr(newPort->portBits.rowBytes * (long) (inBounds->bottom - inBounds-°dONLNdΩ»r*
  6174.            >top));°dONLNd«“≤*
  6175. R  if (MemError()!=noErr) {   /* check to see if we had enough room for the bits */°dONLNdf—‹Ü*
  6176.     SetPort(savePort);°dONLNd}€ÊN*
  6177. >    ClosePort(newPort);      /* dump the visRgn and clipRgn */°dONLNdºÂ*
  6178. 4    DisposPtr((Ptr)newPort); /* dump the GrafPort */°dONLNdÒÔ˙0*
  6179. 8    return false;            /* tell caller we failed */°dONLNd*˘1*
  6180.     }°dONLNd0Ä*
  6181. H  /* since the bits are just memory, let's clear them before we start */°dONLNdy
  6182. ô*
  6183. M  EraseRect(inBounds);     /* OpenPort did a SetPort(newPort) so we are ok */°dONLNd«"ö*
  6184.   *newOffscreen = newPort;°dONLNd‚!,|*
  6185.   SetPort(savePort);°dONLNd˜+6D*
  6186. <  return true;               /* tell caller we succeeded! */°dONLNd45@*
  6187. }
  6188. °dONLNd6KW∞*YHere is the function to get rid of an off-screen bitmap created by the previous function:
  6189.     °dONLNdêcn
  6190. *1void DestroyOffscreenBitMap(GrafPtr oldOffscreen)°dONLNd¬mx*
  6191. {°dONLNdƒwÇ≤*
  6192. R  ClosePort(oldOffscreen);                       /* dump the visRgn and clipRgn */°dONLNdÅål*
  6193. D  DisposPtr(oldOffscreen->portBits.baseAddr);    /* dump the bits */°dONLNd\ãñl*
  6194. D  DisposPtr((Ptr)oldOffscreen);                  /* dump the port */°dONLNd°ï†*
  6195. }
  6196. °dONLNd£´∑è*HNow that you know how to create and destroy an off-screen bitmap, let’s °dONLNdδè∑⁄(”≠go through the°dONLNd˙∏ƒ^(‡6Dmotions of using one.  First, let’s define a few things to make the °dONLNd>∑^√§(‡|
  6197. _NewWindow°dONLNdH∏§ƒº)F call °dONLNdN∏ºƒ⁄)a little°dONLNdWƒ–;(Ï6clearer.
  6198.     °dONLNd`‹Áã*#define kIsVisible true°dONLNdxÊÒã*
  6199. #define kNoGoAway false°dONLNdê˚ü*
  6200. #define kNoWindowStorage 0L°dONLNd¨˙÷*
  6201. &#define kFrontWindow ((WindowPtr) -1L)
  6202. °dONLNd”±*!Here’s the body of the test code:
  6203.     °dONLNdı(36*main()°dONLNd¸2=*
  6204. {°dONLNd˛<G0*
  6205. 8  char* myString = "\pThe EYE";  /* string to display */°dONLNd7P[D*<  GrafPtr   offscreen;           /* our off-screen bitmap */°dONLNdtZeS*
  6206. ?  Rect      ovalRect;            /* used for example drawing */°dONLNd¥do:*
  6207. :  Rect      myWBounds;           /* for creating window */°dONLNdÔny£*
  6208. O  Rect      OSRect;              /* portRect and bounds for off-screen bitmap*/°dONLNd    ?xÉÅ*
  6209.   WindowPtr myWindow; ¡4¡˘
  6210. *74) of 6(÷ãQD 7 - Off-Screen Bitmaps+    M.QD.OffscreenBitMapsˇ<◊#ˇ ˇˇˇˇ#◊ 
  6211. IR,Times
  6212. .+Z-Developer Support Center(-Û    June 1990 /X/,
  6213. Courier
  6214.     °dONLNd<(r(DZ>  InitToolbox();                 /* exercise for the reader */°dONLNd?'<2r*
  6215. >  myWBounds = qd.screenBits.bounds;  /* size of main screen */°dONLNd~1<<Y*
  6216. 9  InsetRect(&myWBounds, 50,50);  /* make it fit better */°dONLNd∏;<F—*
  6217. Q  myWindow = NewWindow(kNoWindowStorage, &myWBounds, "\pTest Window", kIsVisible,°dONLNd
  6218. E<PÜ*
  6219. B                       noGrowDocProc, kFrontWindow, kNoGoAway, 0);°dONLNdMO<Z|*
  6220. @  if (!CreateOffscreenBitMap(&offscreen, &myWindow->portRect)) {°dONLNdéY<dá*
  6221.     SysBeep(1);°dONLNdûc<nñ*
  6222.     ExitToShell();°dONLNd±m<xU*
  6223.     }°dONLNd∑w<Ç'*
  6224. /  /* Example drawing to our off-screen bitmap*/°dONLNdÁÅ<å•*
  6225.   SetPort(offscreen);°dONLNd˝ã<ñ«*
  6226. O  OSRect = offscreen->portRect;  /* offscreen bitmap's local coordinate rect */°dONLNdMï<††*
  6227.   ovalRect = OSRect;°dONLNdbü<™‹*
  6228.    FillOval(&ovalRect, qd.black);°dONLNdÉ©<¥“*
  6229.   InsetRect(&ovalRect, 1, 20);°dONLNd¢≥<æ‹*
  6230.    FillOval(&ovalRect, qd.white);°dONLNd√Ω<»“*
  6231.   InsetRect(&ovalRect, 40, 1);°dONLNd‚«<“‹*
  6232.    FillOval(&ovalRect, qd.black);°dONLNd—<‹ü*
  6233. G  MoveTo((ovalRect.left + ovalRect.right - StringWidth(myString)) >> 1,°dONLNdK€<ÊE*
  6234. 5         (ovalRect.top + ovalRect.bottom - 12) >> 1);°dONLNdÅÂ<õ*
  6235.   TextMode(srcXor);°dONLNdïÔ<˙Ø*
  6236.   DrawString(myString);°dONLNd≠<Ã*P  /* copy from the off-screen bitmap to the on-screen window.  Note that in this°dONLNd˛
  6237. <∏*
  6238. L  case the source and destination rects are the same size and both cover the°dONLNdK<"≥*
  6239. K  entire area.  These rects are allowed to be portions of the source and/or°dONLNdó!<,—*
  6240. Q  destination and do not have to be the same size.  If they are not the same size°dONLNdÈ+<6"*
  6241. .  then _CopyBits scales the image accordingly.°dONLNd5<@P*
  6242.   */°dONLNd?<J†*
  6243.   SetPort(myWindow);°dONLNd2I<TO*
  6244. 7  CopyBits(&offscreen->portBits, &(*myWindow).portBits,°dONLNdjS<^ï*
  6245. E           &offscreen->portRect, &(*myWindow).portRect, srcCopy, 0L);°dONLNd∞g<r§*H  DestroyOffscreenBitMap(offscreen);    /* dump the off-screen bitmap */°dONLNd˘q<|§*
  6246. H  while (!Button());     /* give user a chance to see our work of art */°dONLNdB{<ÜA*
  6247. }
  6248. °dONLNdDù<¨Ä*&Comments
  6249. °dONLNdMπ<≈‰*%In the example code, the bits of the °dONLNdr∏‰ƒ)®BitMap°dONLNdxπ≈§)*! structure, which are pointed to °dONLNdôπ§≈Δ)ñby the °dONLNd†∏Δƒ˛)"baseAddr°dONLNd©Δ<“±(ÓZfield, are allocated by a °dONLNd√≈±—‚)u_NewPtr°dONLNd Δ‚“å)1% call.  If your off-screen bitmap is °dONLNdÔΔ哞)™close to the size of the°dONLNd“<fiS(˙Z:screen, then the amount of memory needed for the bits can °dONLNdB“Sfi˛(˙q#be quite large (on the order of 20K°dONLNdffi<ÍE(Z8for the Macintosh SE or 128K for a large screen).  This °dONLNdûfiEͲ(c%is quite a lot of memory to lock down°dONLNdƒÍ<ˆÍ(Z'in your heap and it can easily lead to °dONLNdÎÍ͈˛)Æ9fragmentation if you intend to keep the off-screen bitmap°dONLNd%ˆ<⁄(ZXaround for any length of time.  One alternative that lessens this problem is to get the °dONLNd}ˆ⁄˛(¯bits via°dONLNdÜ<Ç(+Z
  6250. _NewHandle°dONLNdêÇ•)F6 so the Memory Manager can move them when necessary.  °dONLNdΔ•˛(+√To implement this°dONLNdÿ<¢(8Zapproach, you need °dONLNd΢c)f%to keep the handle separate from the °dONLNd    cõ)¡GrafPort°dONLNd    õ˛)8 (for example, in a°dONLNd    ,<)|(EZstructure that °dONLNd    ;|)∂)@ combines a °dONLNd    F∂(Ó):GrafPort°dONLNd    NÓ))8 and a °dONLNd    U(:)"Handle°dONLNd    [:)˛)*').  When you want to use the off-screen°dONLNd    É*<67(RZ2bitmap you would then lock the handle and put the °dONLNd    µ*76Δ)˚dereferenced handle into the °dONLNd    “)Δ5˛)èbaseAddr°dONLNd    €6<B¢(^ZLfield.  When you are not using the off-screen bitmap you can then unlock it.°dONLNd
  6251. (N<ZÂ*"This example does not demonstrate °dONLNd
  6252. JNÂZ˛)©9one of the more typical uses of off-screen bitmaps, which°dONLNd
  6253. ÑZ<fW(ÇZis to °dONLNd
  6254. äZWf˛)Opreserve the contents of windows so that after a temporary window or dialog box°dONLNd
  6255. ⁄f<r˘(éZ%obscures part of your windows and is °dONLNd
  6256. ˇf˘r˛)Ω4then dismissed, you can quickly handle the resulting°dONLNd 4r<~†(öZJupdate events without recreating all of the intermediate drawing commands. ¡X¡
  6257. *<QD 7 - Off-Screen Bitmaps(÷5) of 6(ÏZM.QD.OffscreenBitMapsˇ¥◊#ˇ ˇˇˇˇ#◊ 
  6258. IR,Times
  6259. .+6-Macintosh Technical Notes /4/˘
  6260. °dONLNd)V*DMake sure you only restore the pixels within the content regions of °dONLNdDV)⁄(Etyour own windows in case°dONLNd])5€(Q6%the temporary window partly obscures °dONLNdÇ)€5⁄)√1windows belonging to other applications or to the°dONLNd¥5A√(]6$desktop.  Another application could °dONLNdÿ5√A⁄)´8change the contents of its windows while they are behind°dONLNdAMP(i6<your temporary window, so you cannot simply restore all the °dONLNdMAPM⁄(inpixels that were behind the°dONLNdiMYM(u6
  6261. temporary °dONLNdsMMY⁄)5Mwindow because that would restore the old contents of the other application’s°dONLNd¡Yew(Å6windows.  Instead, °dONLNd‘Ywe⁄)_Eyou could keep keep an off-screen bitmap for each of your windows and°dONLNdeqR(ç6
  6262. then restore °dONLNd'eRq⁄):Lthem by copying each bit map into the corresponding window’s ports when they°dONLNdtq}Ö(ô6get their update events.°dONLNdçâï|*An alternate method °dONLNd°â|ï⁄)dGis to make a single off-screen bitmap that is as large as the temporary°dONLNdÈï°û(Ω6Nwindow and a region that is the union of the content regions of your windows. °dONLNd7ïû°⁄(Ωº  Before you°dONLNdC°≠(…63display the temporary window, copy the screen into °dONLNdv°≠⁄)¯*the off-screen bit map using the region as°dONLNd°≠π
  6263. (’62a mask.  After the temporary window is dismissed, °dONLNd”≠
  6264. π⁄)ı)restore the obscured area by copying from°dONLNd˝π≈I(·6?the off-screen bit map into a copy of the Window Manager port, °dONLNd<πI≈⁄(·gand use the region as a mask.°dONLNd[Δ“˘(Ó61If the region has the proper shape and location, °dONLNdåΔ˘“/)· it prevents ,
  6265. Courier°dONLNdò≈/—n)6    _CopyBits°dONLNd°Δn“⁄)? from drawing outside°dONLNd∑“fiÌ(˙6)of the content regions of your windows.  °dONLNd‡“Ìfi⁄)’,See Technical Note #194, WMgrPortability for°dONLNd
  6266. fiÍ—(6%details about drawing across windows.°dONLNd3ˆy*In some cases it can °dONLNdHˆy⁄)aIbe just as fast and convenient to simply define a picture (PICT) and then°dONLNdíú(*6Ldraw it into your window when necessary.  There are cases, however, such as °dONLNdfiú⁄(*∫text rotation,°dONLNdÌL(66 where it is °dONLNd˘L⁄)4Qadvantageous to do the drawing off the screen, manipulate the bit image, and then°dONLNdK&…(B6© the result to the visible window °dONLNdq…&⁄)±:(thus avoiding the dangers inherent in writing directly to°dONLNd¨&2b(N6Jthe screen).  In addition, this technique reduces flicker, because all of °dONLNdˆ&b2⁄(NÄthe drawing done off the°dONLNd2>Δ(Z6%screen appears on the screen at once.°dONLNd5JV&*;It is also important to realize that, if you plan on using °dONLNdpJ&V⁄(rD#the pre-Color QuickDraw eight-color°dONLNdîVb}(~6model, an off-screen °dONLNd©V}b⁄)eFbitmap loses any color information and you do not see your colors on a°dONLNdbnÃ(ä6^system that is capable of displaying them.  In this case you should either use a PICT to save °dONLNdNbÃn⁄(äÍthe°dONLNdRnzc(ñ6Adrawing information or check for the presence of Color QuickDraw °dONLNdìncz⁄(ñÅand, when it is present,°dONLNd¨{á3(£6use a °dONLNd≤z3Ü])PixMap°dONLNd∏{]áô)* instead of a °dONLNdΔzôÜ√)<BitMap°dONLNdÃ{√á)* and the color °dONLNd€{áK)Ctoolbox calls (°dONLNdÍ{Káù)EInside Macintosh°dONLNd˙{ùá⁄)R , Volume V)°dONLNd    áì⁄(Ø6)instead of the standard QuickDraw calls (°dONLNd    /á⁄ì+)¬Inside Macintosh°dONLNd    ?á+ìf)Q , Volume I).°dONLNd    Lü´\(«6
  6267. You may also °dONLNd    Yü\´⁄)DKwant to refer to the OffScreen library (DTS Sample Code #15) which provides°dONLNd    •´∑P(”6 both high- °dONLNd    ∞´P∑⁄)8Iand low-level off-screen bitmap support for the 128K and later ROMs.  The°dONLNd    ˙∑√•(fl6QOffSample application (DTS Sample Code #16) demonstrates the use of this library.°dONLNd
  6268. LÁÛÇ*0Further Reference: 4˘°dONLNd
  6269. _Ù*.+
  6270. •°dONLNd
  6271. aÙ<ç)Inside Macintosh°dONLNd
  6272. qÙç)Q, Volumes I & IV, QuickDraw°dONLNd
  6273. ç* .((H•°dONLNd
  6274. è< ç)Inside Macintosh°dONLNd
  6275. üç )Q, Volume V, Color QuickDraw°dONLNd
  6276. ª *.(4H•°dONLNd
  6277. Ω <
  6278. )(Technical Note M.IM.PrincipiaOffscreen —°dONLNd
  6279. Ë`$4+$ *Principia Off-Screen Graphics Environments°dONLNd $*0.(LH•°dONLNd $<0È)Technical Note M.TB.WMgrPort —°dONLNd 60`<≥+$  WMgrPortability°dONLNd G<*H.(dH•°dONLNd I<<Ho)9DTS Macintosh Sample Code #15, OffScreen & #16, OffSample ¡4¡˘
  6280. (÷66) of 6(÷ãQD 7 - Off-Screen Bitmaps+    M.QD.OffscreenBitMapsˇ¿◊#ˇ ˇˇˇˇ#◊†Ç 
  6281. /ZÅ#
  6282.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6283. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6284. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6285. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6286. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6287.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6288. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  6289. IR.°dONLNdn<Å(õZQD 8 - Old-Style Colors
  6290. °dONLNdÄ<èá*    QuickDraw
  6291. °dONLNd#õ<ßt* Revised by:°dONLNd/õÑßÀ)H
  6292. Bill Guschwan°dONLNd=õŒß˛(√ÏMay 1993°dONLNdFß<≥q(œZ Written by:°dONLNdRßÑ≥T)H)Rich “I See Colors” Collyer and Byron Han°dONLNd|ßæ≥˛(œ‹ October 1989°dONLNdâø<ÀÙ(ÁZ'This Technical Note covers limitations °dONLNd∞øÙÀ˛)∏8of the original Macintosh color model (eight-color) that°dONLNdÈÀ<◊ç(ÛZInside Macintosh°dONLNd˘Àç◊ó)Q4 Volume I, page I-173, QuickDraw, does not document.°dONLNd.„<Ô·( ZChanges since October 1989:°dONLNdKÔ<˚
  6293. * -Added definitions of the old-style constants.°dONLNdy˚<ô* KCorrected definitions of old-style constants to reflect MPW 3.2 interfaces. 2X2°dONLNdΔ <,Ê*%QQuickDraw has always been able to deal with color, just on a very limited basis. °dONLNd Ê,˛(HMost°dONLNd,<8Õ(TZLapplications have not made use of this feature, since Color QuickDraw–based °dONLNdh,Õ8˛(TΠ   Macintosh°dONLNdr8<D¨(`Zcomputers come with a °dONLNdà8¨D˛)pEbetter color model. There are, however, a few nice features that come°dONLNdŒD<Pó(lZwith the old-style °dONLNd·DóP˛)[Gcolor model. With the old-style colors, it is easy to print color on an°dONLNd)P<\=(xZ3ImageWriter with a color ribbon. Another advantage °dONLNd\P=\˛(x['is that developers do not have to write°dONLNdÑ\<h∏(ÑZLspecial-case code depending on whether or not a machine has Color QuickDraw.°dONLNd—t<Äé*GNow that you are ready to convert to the old-style colors, there are a °dONLNdtéIJ(ú¨few things you should°dONLNd.Ä<åZ(®Zknow °dONLNd3ÄZå˛)Wabout that do not work with old-style colors. This Note covers the limitations of using°dONLNdãå<òú(¥ZLold-style colors, as well as the best ways to work around these limitations.
  6294. °dONLNdÿ∞<øà*' Limitations
  6295. °dONLNd‰À<◊k*    The most °dONLNdÌÀk◊˛)/Vobvious limitation is that of only eight colors: black, white, red, green, blue, cyan,°dONLNdD◊<„Ø(ˇZNyellow, and magenta. This limitation is a problem only if you want to produce °dONLNdí◊Ø„˛(ˇÕa color-intensive°dONLNd§„<Ôı( Zaapplication; if this describes your application, then you need not read any further in this Note.°dONLNd˚<*3The next limitation is that off-screen buffers are °dONLNd9˚˛)„-not very useful. You can draw into off-screen°dONLNdg<4(/Z4buffers, but there is no way to get the colors back °dONLNdõ4˛)¯)from the buffer. This leads into the next°dONLNd≈< Æ(<Zlimitation, which is that ,
  6296. Courier°dONLNdflÆÌ)r    _CopyBits°dONLNdËÌ ∏)?+ cannot copy more than one color at a time.°dONLNd-<9Ü(UZWhen you call °dONLNd",Ü8≈)J    _CopyBits°dONLNd+-≈9û)?+ from an off-screen buffer to your window, °dONLNdV-û9˛)Ÿyou need to set the°dONLNdj:<F:(bZ7forecolor to the color you want to copy before calling °dONLNd°9:Ey)˛    _CopyBits°dONLNd™:yFÀ)? (for example, to °dONLNdº:ÀF˛)R
  6297. copy a red°dONLNd«G<Sr(oZ
  6298. object, call °dONLNd‘FrR˛)6_ForeColor(redColor)°dONLNdËG˛S§)å!). Now when you copy the object, °dONLNd    G§S˛)¶you can copy only°dONLNdS<_({Z)one color. If you copy different colored °dONLNdDS_˛)≈1objects at one time, then you have a problem. The°dONLNdv_<kÛ(áZaresult of a multicolored copy is that all objects copy in the same color, that of the foreground. ¡X¡
  6299. *OQD 8 - Old-Style Colors(÷1) of 4(ÏZM.QD.OldColorsˇ°¿Ù%%DSIDICT:_cv
  6300. currentdict /bu known {bu}if
  6301. userdict /_cv known not{userdict /_cv 30 dict put}if
  6302. _cv begin
  6303. /bdf{bind def}bind def
  6304. currentscreen/cs exch def/ca exch def/cf exch def
  6305. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6306. /ss{//cf //ca //cs setscreen}bdf
  6307. /stg{ss setgray}bdf
  6308. /strgb{ss setrgbcolor}bdf
  6309. /stcmyk{ss cvcmyk}bdf
  6310. /min1{dup 0 eq{pop 1}if}bdf
  6311. end
  6312. currentdict /bn known {bn}if
  6313. †ø|◊#ˇ ˇˇˇˇ#◊ 
  6314. IR,Times
  6315. .+6-Macintosh Technical Notes /4/˘
  6316. °dONLNd) *5It is possible to work with an off-screen buffer and °dONLNd5 )⁄)Ù.the old-style colors, but it requires a lot of°dONLNdd)5ã(Q6Nextra work. Unless the objects are really complex, then it is probably easier °dONLNd≤)ã5⁄(Q©to just draw the°dONLNd√5Aª(]6"objects directly into your window.°dONLNdÊMY…*VOne other limitation does exist. Consider the following code sample. One would assume °dONLNd<M…Y⁄(uÁthat°dONLNdAYe√(Å6$this sample would work at all times.,
  6317. Courier
  6318.     °dONLNdfq|Å*    SetPort (myPort);°dONLNd|{Ü≥*
  6319.     savedFG := myPort^.fgColor;°dONLNdúÖê5*
  6320. 9    ForeColor (redColor);            {or any other color}°dONLNd÷ô§Ã*$    {...drawing takes place here...}°dONLNd˚≠∏ê*    ForeColor (savedFG);
  6321. °dONLNdƒ–Û*-Surprise. It does not always work. The saved °dONLNdAƒÛ–4)€value for the °dONLNdO√4œe)AfgColor°dONLNdVƒe–¢)1 field of the °dONLNdd√¢œ⁄)=grafPort°dONLNdm—›Œ(˘6(is not a classic QuickDraw color if the °dONLNdï–Œ‹)∂grafPort°dONLNdù—›C)8 is actually a °dONLNd¨–C‹Ç)=    cGrafPort°dONLNdµ—Ç›⁄)?. If dealing with a°dONLNd…›ÈW(6    cGrafPort°dONLNd“fiWÍq)?, the °dONLNdÿ›qÈ¢)fgColor°dONLNdflfi¢Í$)1 field actually contains the °dONLNd¸fi$Í⁄)Ç%foreground color’s entry in the color°dONLNd"Θó(6table, so the second call to °dONLNd?Íóˆ›)
  6322. _ForeColor°dONLNdIΛ˜R)F really messes things up.°dONLNdc¿(,6$The proper way to set and reset the °dONLNdá¿î)®*foreground color with classic QuickDraw’s °dONLNd±î⁄)‘
  6323. _ForeColor°dONLNdºj(86call is as follows:
  6324.     °dONLNd–(3Å*    SetPort (myPort);°dONLNdÊ2=≥*
  6325.     savedFG := myPort^.fgColor;°dONLNd<G5*
  6326. 9    ForeColor (redColor);            {or any other color}°dONLNd@P[Ã*$    {...drawing takes place here...}°dONLNdedoè*K    myPort^.fgColor := savedFG;      {Manually stuff the old fgColor back.}°dONLNd±nyû*
  6327. N    If (32BQD = TRUE) Then           {32BQD is a flag that is made and set by}°dONLNdxÉ≤*
  6328. R        PortChanged (myPort);        {the application; to set it, the application}°dONLNdSÇçº*
  6329. T                                     {needs to check _Gestalt for 32-Bit QuickDraw.}
  6330. °dONLNd®ô•≈*&This Note also applies to the routine °dONLNdŒò≈§ )≠
  6331. _BackColor°dONLNdÿô •)F.
  6332. °dONLNd⁄ΩÃj(Ë6
  6333. What Works
  6334. °dONLNdÂÿ‰t*FThe easiest way to work with these limited colors is to use pictures. °dONLNd+ÿt‰⁄(íWhen you draw the°dONLNd=‰I( 6;images, you should draw into a picture. Then when you want °dONLNdx‰I⁄( gto draw the images into your°dONLNdïÒ˝¢(6window or to a printer, call °dONLNd≤¢¸ˆ)ä _DrawPicture°dONLNdæÒˆ˝E)T. Pictures work °dONLNdŒÒE˝⁄)Owell with the old-style colors,°dONLNdÓ˝    å(%6Land you don’t need to worry about making sure that the forecolor is current °dONLNd:˝å    ⁄(%™
  6335. when you draw°dONLNdH    q(16into your window.°dONLNdZ!-ó*TOnce you have the picture, you can use it to draw into the screen or to the printer °dONLNdÆ!ó-⁄(Iµ
  6336. port. You can°dONLNdº.:R(V6
  6337. also set the °dONLNd…-R9¶): WindowRecord°dONLNd’.¶:Ø)Ts °dONLNd◊-Ø9Ó)        windowPic°dONLNd‡.Ó:6)? to equal your °dONLNdÔ-69ë)H
  6338. PictureHandle°dONLNd¸.ë:Ã)[  so updates °dONLNd.Ã:⁄);are°dONLNd :Fπ(b6handled by the Window Manager. ¡4¡˘
  6339. *t2) of 4(÷êQD 8 - Old-Style Colors+M.QD.OldColorsˇ |◊#ˇ ˇˇˇˇ#◊ 
  6340. IR,Times
  6341. .+Z-Developer Support, Palatino)K  Center    (-ÛMay 1993 0X0
  6342. °dONLNd*<9H(UZ#What Do Those Constants Mean Anyway
  6343. °dONLNd$E<Q£*The correct values are,
  6344. Courier
  6345. °dONLNd<]<i~* blackColor °dONLNdH]Ñiê)H= °dONLNdK]®i¥)$33°dONLNdNh<t~(êZ whiteColor °dONLNdZhÑtê)H= °dONLNd]h®t¥)$30°dONLNd`s<l(õZredColor°dONLNdisÑä)H=°dONLNdks®∫)$205°dONLNdo~<äx(¶Z
  6346. greenColor°dONLNdz~Ñää)H=°dONLNd|~®ä∫)$341°dONLNdÄâ<ïr(±Z    blueColor°dONLNdäâÑïä)H=°dONLNdåâ®ï∫)$409°dONLNdêî<†r(ºZ    cyanColor°dONLNdöîцä)H=°dONLNdú∫)$273°dONLNd†ü<´ä(«Z
  6347. magentaColor=°dONLNdÆü®´∫)l137°dONLNd≤™<∂~(“Z yellowColor°dONLNdæ™Ñ∂ä)H=°dONLNd¿™®∂¥)$69
  6348. °dONLNd√¡<ÕL(ÈZ9The following discussion is theoretical and was based on °dONLNd¸¡LÕ˛(Èj#the color constants for the MPW 3.1°dONLNd Õ<ŸP(ıZ<interfaces. Well, those interfaces were wrong as far as the °dONLNd\ÕPŸ˛(ın$color constants. The discussion will°dONLNdÅŸ<ª(Zbe kept here to prove once °dONLNdúŸªÂ˛)Aand for all that Macintosh programming sometimes is arbitrary and°dONLNdfiÂ<Ò¶(
  6349. ZPnot logical. On the other hand, the information about the color bits is correct.°dONLNd/˝<    ã*IEach of the constants contains 9 bits of information, and each bit has a °dONLNdx˝ã    ˛(%©special meaning. Figure°dONLNdê    <g(1Z=1 illustrates the meaning of each of the bits, while Table 1 °dONLNdÕ    g˛(1Öshows how each of the color°dONLNdÈ<!Í(=Z(constants fills in the appropriate bits.†09†Ç
  6350. L√‹≤òS,„S,„L√‹≤Áˇ˛Ç ¸p¸¯p 0Ä ÄÄà`HÊsÄ(  Ñí$Ç¯H` Ñí#à Ñí Ç  Ñí$Ç ¸@ Ñ‚ ÑÄ H x‡¯ 0Áˇ˛˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝@    @  ˝    @  ˝    @  $«    @  %$Ä    @  $‰Ä    @  %$Ä    @  %$Ä    @  ‰Ä    @  ˛˛    @  ˛˚    @  ˜    @  ˜    @  ˜    @  ˛@@    @  ˛¿@    @  ˛LsÊ    @  ˛RîíI    @  ˛NóíG    @  ˛RîI    @  ˛RîíI    @  ˛Ns'    @  ¸˝    @  ¸`˙   @  Ù   @  Ù   @  ˚ f˝   @  ˚ "˝   @  ˚F"2   @  ˚I"J   @  ˙è"IP   @  ˙à"IP   @  ˙â"H†   @  ˙Ü"0†¸
  6351.   @  Ò
  6352.   @  Ò
  6353.   @  Ò
  6354.   @  Ò
  6355.   @  Ò
  6356.   @  ˜0@  @  ˜ê@  @  ˜ëåH  @  ˜RP  @  ˜ë–`  @  ˜íP`  @  ˜íRP  @  ˜ÃH  @  Ó
  6357.  @  Ó
  6358.  @  Ó
  6359.  @  Ó
  6360.  @  Û  @  ÛÄ  @  Ûò‡ @  Û•  @  Û=  @  Û
  6361. !  @  Û    %  @  Ûò‡ @  Ó
  6362.  @   Î@   Î@   Î@  Ò¸@  ÒÄ˝@  Ò
  6363. c@  Ò
  6364. îí@  Ò
  6365.     ê˜í@  Ò
  6366. êÑ@  Ò
  6367. êîí@  Ò
  6368. c@   Î@  Ë  Ë  Ë  Ë  
  6369. ÌyIJ  
  6370. ÌDIJ  
  6371. Ì    Dâ0  
  6372. Ì    xâH  
  6373. Ì    Dâx  
  6374. Ì    Dâ@  
  6375. Ì    DâH  
  6376. Ì    xá0  Ë  Ë  Â Â Â Â  Ù@ı  ˙¸    áò ` $˛ ˙¸    ÑH Ä"$˛ ˙âã1ÅHΔ$ù¿G3òé ˙äLJAâ)(HÄDë$I ˙S»3¡HË0ÚHÄDë<‚I ˙R
  6377. I(0HÄÑë I ˙"HJ@ÑI)(HÄÑë$I ˙!à1ÄáàÊ$àÑÑêòâ 
  6378. Ù@¸˘     Ó˘ „„„„„„ÒÄı@˜0@ à3 ˜êê@ D ˜ìv1ëåHí9ú¿ Ó˜TòIIRPí™$â D˜TêI9ë–a‰í™$âÁíD˜4êIIíP`íD$âD˜4êIIíRPíD$â D ˜I9ÃH D$Ñ¿ D  Òĸ ˚@Î@˙†É
  6379. IR°dONLNd…‘’e+ò¥Figure 1—Bit Definitions°dONLNd+Ì«˘s(ÂTable 1  Color-Bit Correlation
  6380. °dONLNdKñ∞(-¥black°dONLNdQπ‘)#white°dONLNdWȘ)0red°dONLNd[*)'green°dONLNda?T)/blue°dONLNdflÇ)-cyan°dONLNdkê∏)$magenta°dONLNds¿·)0yellow°dONLNd{ñ™(8¥(33)°dONLNdÄΩ—)'(30)°dONLNdÖ„˝)&(209)°dONLNdã*)-(329)°dONLNdë=W)-(389)°dONLNdójÑ)-(269)°dONLNdùó±)-(149)°dONLNd£«€)0(89) :|:°dONLNd®`(u(D~Cyan°dONLNd≠ü(§)?0°dONLNdØ√(»)$0°dONLNd±Î()(0°dONLNd≥()-1°dONLNdµA(F))1°dONLNd∑w(|)61°dONLNdπ§(©)-0°dONLNdªÃ(—)(0°dONLNdΩ'`3Ç(O~Magenta°dONLNd≈'ü3§)?0°dONLNd«'√3»)$0°dONLNd…'Î3)(1°dONLNdÀ'3)-0°dONLNdÕ'A3F))1°dONLNdœ'w3|)60°dONLNd—'§3©)-1°dONLNd”'Ã3—)(0°dONLNd’2`>}(Z~Yellow°dONLNd‹2ü>§)?0°dONLNdfi2√>»)$0°dONLNd‡2Î>)(1°dONLNd‚2>)-1°dONLNd‰2A>F))0°dONLNdÊ2w>|)60°dONLNdË2§>©)-0°dONLNdÍ2Ã>—)(1°dONLNdÏ=`Iv(e~Black°dONLNdÚ=üI§)?1°dONLNdÙ=√I»)$0°dONLNdˆ=ÎI)(0°dONLNd¯=I)-0°dONLNd˙=AIF))0°dONLNd¸=wI|)60°dONLNd˛=§I©)-0°dONLNd=ÃI—)(0°dONLNdH`To(p~Red°dONLNdHüT§)?0°dONLNdH√T»)$1°dONLNd
  6381. HÎT)(1°dONLNd HT)-0°dONLNdHATF))0°dONLNdHwT|)60°dONLNdH§T©)-1°dONLNdHÃT—)(1°dONLNdS`_w({~Green°dONLNdSü_§)?0°dONLNdS√_»)$1°dONLNd SÎ_)(0°dONLNd"S_)-1°dONLNd$SA_F))0°dONLNd&Sw_|)61°dONLNd(S§_©)-0°dONLNd*SÃ_—)(1°dONLNd,^`jr(Ü~Blue°dONLNd1^üj§)?0°dONLNd3^√j»)$1°dONLNd5^Îj)(0°dONLNd7^j)-0°dONLNd9^AjF))1°dONLNd;^wj|)61°dONLNd=^§j©)-1°dONLNd?^Ãj—)(0°dONLNdAi`u|(ë~Inverse°dONLNdIiüu§)?0°dONLNdKi√u»)$1°dONLNdMiÎu)(0°dONLNdOiu)-0°dONLNdQiAuF))0°dONLNdSiwu|)60°dONLNdUi§u©)-0°dONLNdWiÃu—)(0°dONLNdYt`Ä~(ú~Normal°dONLNd`tüħ)?1°dONLNdbt√Ä»)$0°dONLNddtÎÄ)(1°dONLNdftÄ)-1°dONLNdhtAÄF))1°dONLNdjtwÄ|)61°dONLNdlt§Ä©)-1°dONLNdntÃÄ—)(1 ¡X¡(÷ZQD 8 - Old-Style Colors(÷3) of 4(ÏZM.QD.OldColorsˇ◊#ˇ ˇˇˇˇ#◊ 
  6382. IR,Times
  6383. .+6-Macintosh Technical Notes /4/˘
  6384. °dONLNd)5Ç*$Further Reference: T4T˘°dONLNdB*N.+•°dONLNdB<Nç)Inside Macintosh°dONLNd%BçN7)Q!, Volume I, page I-173, QuickDraw°dONLNdGN*Z.(vH•°dONLNdIN<ZÅ)<Technical Note M.IM.Copybits—Of Time and Space and _CopyBits ¡4¡˘
  6385. (÷64) of 4(÷êQD 8 - Old-Style Colors+M.QD.OldColorsˇ◊#ˇ ˇˇˇˇ#◊†Ç 
  6386. /ZÅ#
  6387.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6388. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6389. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6390. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6391. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6392.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6393. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  6394. IR.°dONLNdn<Å‘(õZ.QD 9 - Palette Manager Changes in System 6.0.2
  6395. °dONLNd/Ä<èá*    QuickDraw
  6396. °dONLNd:õ<ßq* Written by:°dONLNdFõÑߌ)HGuillermo Ortiz°dONLNdVõæß˛(√‹ October 1988°dONLNdc≥<øl(€Z>This Technical Note describes the changes and enhancements to °dONLNd°≥lø˛(€äthe Palette Manager in System°dONLNdøø<ÀÊ(ÁZ#Software 6.0.2 and future versions. ˆXˆ
  6397. °dONLNd„<ˇª*4Application Palette
  6398. °dONLNd˜ <ö*MApplications now have the ability to define a default palette for the system °dONLNdD ö˛(3∏to use when it needs°dONLNdY<#Û(?Z'to define the color environment (i.e., °dONLNdÄÛ#˛)∑4when it creates a color window without an associated°dONLNdµ#</÷(KZ"palette or displays a dialog box).°dONLNdÿ;<G2*6The application palette feature is especially cool in °dONLNd;2G˙)ˆ(cases where a color application uses old°dONLNd6;˙G˛)»-°dONLNd7G<Sfi(oZYstyle dialogs and alerts because without an application palette, the system will use the °dONLNdêGfiS˛(o¸default°dONLNdòS<_˝({Z)palette to define the color environment. °dONLNd¡S˝_˛)¡5 Since the system uses the default palette, the color°dONLNd˜_<kì(áZenvironment may °dONLNd_ìkΩ)Wchange (°dONLNd_Ωkœ)*will°dONLNd_œk˛): change in 16-color mode) to cause some “cosmic” colors to°dONLNdNk<wˆ(ìZ'appear in the active window.  Defining °dONLNdukˆw˛)∫8a default application palette with two colors, black and°dONLNdÆw<ÉΩ(üZwhite, solves this problem.°dONLNd è<õÔ*(If the system needs a palette to define °dONLNdÚèÔõ˛)≥9a color environment, it looks in the resource fork of the°dONLNd,ú<®î(ƒZapplication for the ,
  6399. Courier°dONLNd@õîß⁄)X
  6400. 'pltt' ID °dONLNdJõ⁄߯)F= 0 °dONLNdNú¯®˛)8resource and uses the palette which it contains.  If the°dONLNdá®<¥`(–Zsystem °dONLNdé®`¥˛)$Ycannot find this resource in the application’s resource fork, it will use its own default°dONLNd˵<¡å(›Zpalette (resource °dONLNd˙¥å¿Ó)P'pltt' ID = 0 °dONLNdµÓ¡Q)bin the System file) if °dONLNdµQ¡˛)c&present, or, if necessary, it will use°dONLNdF¡<ÕÎ(ÈZ'the Palette Manager’s built-in palette.°dONLNdn⁄<ʆ*>Once an application has set its color environment (by calling °dONLNd¨Ÿ†ÂÊ(æ
  6401. _InitMenus°dONLNd∂⁄ÊÊÙ)F, °dONLNd∏⁄ÙÊ˛)or°dONLNdªÊ<Úó(Z
  6402. _InitPalettes°dONLNd»ÁóÛƒ)[
  6403.  in weird °dONLNd“ÁƒÛ˛)-Binstances when there are no menus) it can find the default palette°dONLNdÙ<o(Z by calling °dONLNd Ûoˇ>)3GetPalette ( WindowPtr (-1) )°dONLNd=Ù>´)œ or change the default °dONLNdTÙ´˛)mpalette by calling°dONLNdg< £()Z/SetPalette ( WindowPtr (-1), newDefPltt, true )°dONLNdñ£
  6404. ÷()¡.  Note °dONLNdû÷
  6405. ˛)3that the°dONLNdß<ñ(6Zinitialization of the °dONLNdΩñ))ZPalette Manager with a call to °dONLNd‹
  6406. )o)ì
  6407. _InitMenus°dONLNdÊo·)F is contrary to the way °dONLNd˛·˛)rInside°dONLNd<&m(BZ    Macintosh°dONLNdm&N)1-, Volume V, The Palette Manager documents it.
  6408. °dONLNd<><Mfi(iZOne Palette, Many Ports
  6409. °dONLNdTZ<fÑ* You can now °dONLNd`ZÑf*)H associate one palette with many °dONLNdÄY*ei)¶    CGrafPort°dONLNdâZifÜ)? and °dONLNdéYÜe∑)CWindow°dONLNdïZ∑f˛)1 records, thus°dONLNd§f<r¶(éZsimplifying the use of °dONLNdªf¶r˛)jEa single palette with multiple ports and windows; System Software 6.0°dONLNdr<~è(öZKand earlier require copies of the palette to use it with different windows. ¡X¡
  6410. *<.QD 9 - Palette Manager Changes in System 6.0.2(÷1) of 3(ÏZM.QD.PaletteManagerChangesˇ°¿Ù%%DSIDICT:_cv
  6411. currentdict /bu known {bu}if
  6412. userdict /_cv known not{userdict /_cv 30 dict put}if
  6413. _cv begin
  6414. /bdf{bind def}bind def
  6415. currentscreen/cs exch def/ca exch def/cf exch def
  6416. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6417. /ss{//cf //ca //cs setscreen}bdf
  6418. /stg{ss setgray}bdf
  6419. /strgb{ss setrgbcolor}bdf
  6420. /stcmyk{ss cvcmyk}bdf
  6421. /min1{dup 0 eq{pop 1}if}bdf
  6422. end
  6423. currentdict /bn known {bn}if
  6424. †øx◊#ˇ ˇˇˇˇ#◊ 
  6425. IR,Times
  6426. .+6-Macintosh Technical Notes /4/˘
  6427. °dONLNd)O*CAlthough this ability to associate one palette with multiple ports °dONLNdCO)⁄(Emand windows will allow the°dONLNd^*6P(R6
  6428. use of calls °dONLNdk*P6e)8like ,
  6429. Courier°dONLNdp)e5π) _PmForeColor°dONLNd|*π6“)T and °dONLNdÅ)“5&) _PmBackColor°dONLNdç*&6Q)T
  6430. , calling °dONLNdó)Q5¡)+_ActivatePalette°dONLNdß*¡6⁄)p with°dONLNd≠6B@(^6Ban off-screen port does nothing, and as a result, calling it with °dONLNdÔ6@B⁄(^^!an off-screen port will associate°dONLNdBNé(j6Qthe palette with the port but will not cause any change in the color environment.°dONLNdc[g*2One important implication of this feature is that °dONLNdïZf[)Ë
  6431. DisposeWindow°dONLNd¢[[gd)[ (°dONLNd§Zdfø)    
  6432. _DisposWindow°dONLNd±[øg⁄)[) will°dONLNd∏gs1(è6=not dispose of the associated palette automatically since it °dONLNdıg1s⁄(èO"may be allocated to other ports or°dONLNdsƒ(õ6Iwindows.  The only exception to this behavior is when an application has °dONLNdasƒ⁄(õ‚used°dONLNdfãz(®6_GetNewCWindow°dONLNdtÄzå)b" to create the window, there is a °dONLNdñã=)ô'pltt'°dONLNdúÄ=åæ)* resource with the same ID °dONLNd∑Äæå⁄)Åas the°dONLNdæçô‰(µ6+window, and the application has not called °dONLNdÈå‰ò1)à _GetPalette°dONLNdÙç1ôÅ)M for the window.
  6433. °dONLNd±¿w(‹6
  6434. Color Updates
  6435. °dONLNdÕŸ*1System version 6.0.2 also introduces a new call, °dONLNdDÃÿm(ı7 _NSetPalette°dONLNdPÕmŸ⁄)T, which complements°dONLNddŸÂe(6 _SetPalette°dONLNdo⁄eÊs)M.  °dONLNdrŸs«) _NSetPalette°dONLNd~⁄«Ê`)T has the same functionality as °dONLNdùŸ`Â≠)ô _SetPalette°dONLNd®⁄≠Ê⁄)M    , but the°dONLNd≤ÊÚP(6CUpdates°dONLNd∫ÁPÛˇ)8$ parameter has been modified from a °dONLNdfiÊˇÚ0)ØBoolean°dONLNdÂÁ0ÛM)1 to an °dONLNdÏÊMÚ~)Integer°dONLNdÛÁ~Ûµ)1  as follows:
  6436.     °dONLNdˇ
  6437. {(&6GPROCEDURE NSetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;°dONLNdI    <†+$
  6438. nCUpdates: INTEGER);°dONLNd^Y(:6
  6439. INLINE $AA95;
  6440. °dONLNdl)5l* _NSetPalette°dONLNdx*l6o)T °dONLNdy*o6)$changes the palette associated with °dONLNdù)5Y)´    dstWindow°dONLNd¶*Y6j)? to °dONLNd™)j5∞)
  6441. srcPalette°dONLNd¥*∞6⁄)F
  6442. .  It also°dONLNdø6B`(^6@records whether the window wants to receive updates as a result °dONLNdˇ6`B⁄(^~of a change to its color°dONLNdCO¶(k6environment.  If you want °dONLNd2B¶NÂ)é    dstWindow°dONLNd;CÂOÎ)? °dONLNd<CÎO⁄),to be updated whenever its color environment°dONLNdiP\W(x6
  6443. changes, set °dONLNdvOW[ñ)?    nCUpdates°dONLNdPñ\ß)? to °dONLNdÉOß[˚) pmAllUpdates°dONLNdèP˚\)T.  If °dONLNdïP\⁄)'you are only interested in updates when°dONLNdΩ\hW(Ö6    dstWindow°dONLNdΔ]Wifi)? is the active window, set °dONLNd·\fih)á    nCUpdates°dONLNdÍ]i0)? to °dONLNdÓ\0h}) pmFgUpdates°dONLNd˘]}iã)M.  °dONLNd¸]ãi⁄)If you are only°dONLNd jv§(í6interested in updates when °dONLNd'i§u„)å    dstWindow°dONLNd0j„vÈ)? °dONLNd1jÈvã)is not the active window, set °dONLNdOiãu )¢    nCUpdates°dONLNdXj v⁄)? to°dONLNd\vÇe(ü6 pmBkUpdates°dONLNdgweÉi)M.
  6444.     °dONLNdièö∏(∂6 { NSetPalette Update Constants }°dONLNd䣯^*pmNoUpdates = °dONLNdô£ÑÆ¢)l$8000;°dONLNd†£®Ɖ)$ {no updates}°dONLNd≠≠∏^(‘6pmBkUpdates = °dONLNdº≠Ñ∏¢)l$A000;°dONLNd√≠®∏%)${background updates only}°dONLNd›∑¬^(fi6pmFgUpdates = °dONLNdÏ∑Ѭ¢)l$C000;°dONLNdÛ∑®¬%)${foreground updates only}°dONLNd
  6445. ¡Ãc(Ë6pmAllUpdates = °dONLNd¡Ñâ)l$E000;°dONLNd$¡®ÃÈ)$
  6446. {all updates}
  6447. °dONLNd2◊„e(6 _SetPalette°dONLNd=ÿe‰¯)M! retains its syntax and function:
  6448.     °dONLNd_˚v(6FPROCEDURE SetPalette (dstWindow: WindowPtr; srcPalette: PaletteHandle;°dONLNdß˙<õ+$
  6449. CUpdates: Boolean);°dONLNdªY(+6
  6450. INLINE $AA95;
  6451. °dONLNd…'7*Note:°dONLNdœ<'ò)$The trap words for °dONLNd‚ò&Ï)\ _NSetPalette°dONLNdÓÏ')T and °dONLNdÛ&P) _SetPalette°dONLNd˛P'S)M °dONLNdˇS'a)are°dONLNda'è)  identical.
  6452. °dONLNd?Ng(j6 CopyPalette
  6453.     °dONLNdZeI*=PROCEDURE CopyPalette (srcPalette, dstPalette: PaletteHandle;°dONLNdYd<o˙+$
  6454. &srcEntry,dstEntry,dstLength: INTEGER);°dONLNdÄnyY(ï6
  6455. INLINE $AAA1; ¡4¡˘
  6456. *A2) of 3)ı.QD 9 - Palette Manager Changes in System 6.0.2+LM.QD.PaletteManagerChangesˇX◊#ˇ ˇˇˇˇ#◊ 
  6457. IR,Times
  6458. .+Z-Developer Support Center(-Ê October 1988 /X/,
  6459. Courier
  6460. °dONLNd<)ê(FZ _CopyPalette°dONLNd ê*+)T$ is a utility procedure that copies °dONLNd0+)j)õ    dstLength°dONLNd9j*m)? °dONLNd:m*˛)entries from the source palette°dONLNdZ+<7$(SZ1into the destination palette; the copy begins at °dONLNdã*$6\)ËsrcEntry°dONLNdì+\7y)8 and °dONLNdò*y6¬)
  6461. dstEntry, °dONLNd¢+¬7˛)I
  6462. respectively.°dONLNd±7<Cê(`Z _CopyPalette°dONLNdΩ8êD€)TJ will resize the destination palette when the number of entries after the °dONLNd8€D˛(`˘copy is°dONLNdD<PØ(lZgreater than the original.°dONLNd*\<hê* _CopyPalette°dONLNd6]êiƒ)T
  6463.  does not °dONLNd@]ƒi⁄)4call °dONLNdE\⁄hJ)_ActivatePalette°dONLNdU]Ji˛)p$, so the application is free to do a°dONLNdzi<u¡(ëZKnumber of palette changes without causing a series of intermediate changes °dONLNd≈i¡u˛(ëfl to the color°dONLNd“v<Ç(ûZ)environment; the application should call °dONLNd˚uÅt)»_ActivatePalette°dONLNd vtDz)p after completing all palette°dONLNd)Ç<éf(™Zchanges.°dONLNd2õ<߀*%If either of the palette handles are °dONLNdWö€¶)üNIL°dONLNdZõߘ), °dONLNd\ö˜¶K) _CopyPalette°dONLNdhõKßè)T does nothing. ¡X¡
  6464. (÷Z.QD 9 - Palette Manager Changes in System 6.0.2(÷3) of 3(ÏZM.QD.PaletteManagerChangesˇ|◊#ˇ ˇˇˇˇ#◊†Ç 
  6465. /ZÅ
  6466.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6467. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  6468. .R≈R…x(+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  6469. Ω({íDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  6470. 0Ûe(UÎ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  6471.     û?+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  6472. ze(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  6473. IR.°dONLNdn<ŧ(õZ&QD 10 - Picture Comments—The Real Deal
  6474. °dONLNd'Ä<èá*    QuickDraw
  6475. °dONLNd2õ<ßt* Revised by:°dONLNd>õÑß )H
  6476. Joseph Maurer°dONLNdLõæß˛(√‹ October 1992°dONLNdYß<≥q(œZ Written by:°dONLNdeßÑ≥–)HGinger Jernigan°dONLNduß±≥˛(œœ
  6477. November 1986°dONLNdÉø<À‹(ÁZChanges since March 1988: °dONLNdùø‹À>)†This Note (formerly °dONLNd±ø>ÀÚ)b&titled “Optimizing for the LaserWriter°dONLNd◊øÚÀ˛)¥—°dONLNdÿÀ<◊%(ÛZ-PicComments”) describes the picture comments °dONLNdÀ%◊˛)È,defined and interpreted by the Apple printer°dONLNd2◊<„(ˇZdrivers. Most °dONLNd@◊„˛)CNof the picture comments are specific to PostScript, but we renamed the Note to°dONLNdè„<Ôû( ZLemphasize that LaserWriter printers are not necessarily PostScript devices, °dONLNd€„ûÔ˛( ºand that QuickDraw°dONLNdÓÔ<˚—(ZLprinter drivers may implement their own picture comment handling. This Note °dONLNd:Ô—˚˛(Ôhas been°dONLNdC˚< (#ZUcompletely rewritten and incorporates all additional insights gained during the last °dONLNdò˚ ˛(#Ë
  6478. few years.°dONLNd£<`(/ZWe are °dONLNd™`˛)$Qalso much more determined now to discourage the use of obsolete and problem-laden°dONLNd¸<(;Z-(although still supported) picture comments, °dONLNd)˛)Ÿ,and we carefully point out known problems or°dONLNdV<+ƒ(GZlimitations of each comment. VXV
  6479. °dONLNdsP<_è*4 Introduction
  6480. °dONLNdÄl<xR*The ,
  6481. Courier°dONLNdÑkRwÉ)QDProcs°dONLNdãlÉx¿)1
  6482.  record (see °dONLNdòl¿x)=Inside Macintosh°dONLNd®lx∑)R" Volume I, page 197) reflects the °dONLNd l∑x˛)•foundations of°dONLNdŸy<Öì(°Zthe architecture of °dONLNdÌyìÖÁ)WQuickDraw. The °dONLNd¸xÁÑ4)T commentProc°dONLNdy4Ö˛)M+ field points to a procedure that processes°dONLNd3Ü<í^(ÆZ;picture comments, as included in a picture by means of the °dONLNdnÖ^ë§(Æ|
  6483. PicComment°dONLNdxܧí·)F  procedure (°dONLNdÑÜ·í˛)=Inside°dONLNdãí<ûm(∫Z    Macintosh°dONLNdîímû»)1 Volume I, page °dONLNd§í»û˛)[>189). This allows applications to include application-specific°dONLNd„û<™"(ΔZ3additional information in the pictures they create.°dONLNd∑<√R*The °dONLNd∂R¬É)QDProcs°dONLNd"∑É√G)1) record also is the key to understanding °dONLNdK∑G√˛)ƒ#how Macintosh printer drivers work.°dONLNdoƒ<–¬(ÏZWhen the application calls °dONLNdä√¬œ)Ü
  6484. PrOpenPage°dONLNdo)F and draws into the °dONLNd®ƒo–˛)gprinting grafPort, the printer°dONLNd«—<›Z(˘Z9driver collects the drawing commands by hooking into the °dONLNd–Z‹ã(˘xQDProcs°dONLNd—ã›ÿ)1 of the printing °dONLNd—ÿ›˛)Mport. In°dONLNd!fi<Ío(Z particular, °dONLNd-fioÍÎ)3if an application calls the °dONLNdI›ÎÈ1)|
  6485. PicComment°dONLNdSfi1Ͳ)F* procedure while drawing into the printing°dONLNd~Í<ˆ(Z_grafPort, the printer driver gets a chance to capture and process the information contained in °dONLNd›Íˆ˛(the°dONLNd·ˆ<X(Zkind°dONLNd˜Xo) and °dONLNd͈oµ)
  6486. dataHandle°dONLNdÙ˜µÔ)F  parameters.°dONLNd<Œ(7ZDuring the development of the °dONLNdŒ˛)í@original LaserWriter driver, it became obvious that applications°dONLNd`<':(CZ7should be able to take advantage of certain PostScript °dONLNdó:'˛)˛)features that were not accessible through°dONLNd¡'<3¬(OZstandard QuickDraw calls, °dONLNd€'¬3˛)Ü@such as rotated text and graphics, dashed lines, fractional line°dONLNd3<?Å([ZCwidths, and smoothed polygons. Also, certain applications needed a °dONLNd_3Å?˛([üway to transmit their own°dONLNdy?<Kü(gZJnative PostScript instructions to the printer. Picture comments seemed to °dONLNd√?üK˛(gΩbe the ideal vehicle°dONLNdÿK<W—(sZ!for providing these capabilities.°dONLNd˙c<ob*?Unfortunately, there are conflicts with the device-independent °dONLNd    9cbo˛(ãÄ nature of the Macintosh Printing°dONLNd    Zo<{‰(óZ$Manager architecture. In this Note, °dONLNd    ~o‰{˛)®8we still want to document picture comments as completely°dONLNd    ∑{<á∂(£Zand correctly as possible; °dONLNd    “{∂á˛)zDand we want to tell you how to use the best of their features, while ¡X¡
  6487. (÷Z&QD 10 - Picture Comments—The Real Deal(÷ˇ1) of 26(ÏZM.QD.PictCommentsˇ°¿Ù%%DSIDICT:_cv
  6488. currentdict /bu known {bu}if
  6489. userdict /_cv known not{userdict /_cv 30 dict put}if
  6490. _cv begin
  6491. /bdf{bind def}bind def
  6492. currentscreen/cs exch def/ca exch def/cf exch def
  6493. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  6494. /ss{//cf //ca //cs setscreen}bdf
  6495. /stg{ss setgray}bdf
  6496. /strgb{ss setrgbcolor}bdf
  6497. /stcmyk{ss cvcmyk}bdf
  6498. /min1{dup 0 eq{pop 1}if}bdf
  6499. end
  6500. currentdict /bn known {bn}if
  6501. †øö◊#ˇ ˇˇˇˇ#◊ 
  6502. IR,Times
  6503. .+6-Macintosh Technical Notes /4/˘
  6504. °dONLNd)Q*Bmaintaining the important goal of device-independent printing and °dONLNdBQ)⁄(Eoall- purpose PICTs. (This is°dONLNd_)5∫(Q6#why it has such a painful history!)°dONLNdÉAMÎ**First, we give an overview of the picture °dONLNd≠AÎM⁄)”,comments as currently implemented by Apple’s°dONLNd⁄MYz(u6printer drivers. This °dONLNdMzY⁄)bFleads us immediately to the problem section “Cohabitation of QuickDraw°dONLNd7Ye˛(Å6.and PostScript,” which also shows how to keep °dONLNdeY˛e⁄)Ê,the QuickDraw and PostScript graphics states°dONLNdíeqÃ(ç6Zsynchronized during printing. Finally, we discuss all the picture comments by subject, in °dONLNdÏeÃq⁄(çÍthe°dONLNdq}ú(ô6order suggested by Table 1.
  6505. °dONLNd ï§›*'Picture Comments Repertoire
  6506. °dONLNd(∞ºë*LThe following picture comments are recognized by all PostScript LaserWriter °dONLNdt∞ëº⁄(ÿØdrivers version°dONLNdѺ»W(‰63.1 and later.°dONLNdî‘i‡à+Q0Table 1  PostScript LaserWriter Picture Comments°dONLNd»Ïø¯‹+VData °dONLNd—¯.J( LType°dONLNd÷¯ç©)_Kind°dONLNd€¯¿ÿ)3Size°dONLNd‡¯Ù
  6507. )4Data°dONLNd¯AÇ)M Description
  6508.     °dONLNdÚ.V(7L    TextBegin°dONLNd¸çú)_150°dONLNd“◊)E6°dONLNd.)0
  6509. TTxtPicRec°dONLNd
  6510. Aã)?Begin text function°dONLNd".%M(ALTextEnd°dONLNd*ç%ú)_151°dONLNd.“%◊)E0°dONLNd0%)0NIL°dONLNd4A%Ç)?End text function°dONLNdG$./](KL StringBegin°dONLNdS$ç/ú)_152°dONLNdW$“/◊)E0°dONLNdY$/)0NIL°dONLNd]$A/¢)?Begin string delimitation°dONLNdx..9T(UL    StringEnd°dONLNdÇ.ç9ú)_153°dONLNdÜ.“9◊)E0°dONLNdà.9)0NIL°dONLNdå.A9ô)?End string delimitation°dONLNd§8.CX(_L
  6511. TextCenter°dONLNdØ8çCú)_154°dONLNd≥8“C◊)E8°dONLNdµ8C-)0
  6512. TTxtCenter°dONLNd¿8AC¶)?Offset to center of rotation°dONLNdfiL.We(sL
  6513. LineLayoutOff°dONLNdÏLçWú)_155°dONLNdL“W◊)E0°dONLNdÚLW)0NIL°dONLNdˆLAW∏)? Turn LaserWriter line layout off°dONLNdV.ad(}L LineLayoutOn°dONLNd%Vçaú)_156°dONLNd)V“a◊)E0°dONLNd+Va)0NIL°dONLNd/VAa∑)?Turn LaserWriter line layout on°dONLNdO`k(á6#°dONLNdQ`.kq)ClientLineLayout°dONLNdb`çkú)_157°dONLNdf`–k⁄)C16°dONLNdi`k))2    TClientLL°dONLNds`Ak®)?Customize line layout error°dONLNdïjAun*
  6514. distribution°dONLNd£t.W(õL    PolyBegin°dONLNd≠tçú)_160°dONLNd±t“◊)E0°dONLNd≥t)0NIL°dONLNd∑tAò)?Begin special polygon°dONLNdŒ~.âN(•LPolyEnd°dONLNd÷~çâú)_161°dONLNd⁄~“â◊)E0°dONLNd‹~â)0NIL°dONLNd‡~Aâè)?End special polygon°dONLNdıà.ìY(ØL
  6515. PolyIgnore°dONLNdàçìú)_163°dONLNdà“ì◊)E0°dONLNdàì)0NIL°dONLNd
  6516. àAì∂)?Ignore following polygon data°dONLNd)í.ù^(πL
  6517. PolySmooth°dONLNd4íçùú)_164°dONLNd8í“ù◊)E1°dONLNd:íù&)0PolyVerb°dONLNdCíAùÜ)?Close, Fill, Frame°dONLNdWú.ßV(√L    PolyClose°dONLNdaúçßú)_165°dONLNdeú“ß◊)E0°dONLNdgúß)0NIL°dONLNdkúAßà)?Close the polygon°dONLNd~∞.ªZ(◊L
  6518. DashedLine°dONLNdâ∞çªú)_180°dONLNdç∞”ª÷)F-°dONLNdè∞ª3)/ TDashedLine°dONLNdõ∞Aª∂)?Draw following lines as dashed°dONLNdª∫.≈[(·L
  6519. DashedStop°dONLNdΔ∫ç≈ú)_181°dONLNd ∫“≈◊)E0°dONLNdÃ∫≈)0NIL°dONLNd–∫A≈)?End dashed lines°dONLNd‚ƒ.œb(ÎL SetLineWidth°dONLNdÔƒçœú)_182°dONLNdÛƒ“œ◊)E4°dONLNdıƒœ)0Point°dONLNd˚ƒAœ†)?Set fractional line widths°dONLNdÿ.„o(ˇLPostScriptBegin °dONLNd(ÿç„ú)_190°dONLNd,ÿ“„◊)E0°dONLNd.ÿ„)0NIL°dONLNd2ÿA„≠)?Set driver state to PostScript°dONLNdR‚.Ìf(    LPostScriptEnd °dONLNda‚çÌú)_191°dONLNde‚“ÌŸ)E0 °dONLNdh‚Ì)0NIL°dONLNdl‚AÌù)?Restore QuickDraw state°dONLNdÖÏ.˜p(LPostScriptHandle°dONLNdñÏç˜ú)_192°dONLNdöÏ”˜÷)F-°dONLNdúϘ)/PSData °dONLNd§ÏA˜ü)?PostScript data in handle°dONLNdæˆ(6†°dONLNd¿ˆ.e)PostScriptFile°dONLNdœˆçú)_193°dONLNd”ˆ”÷)F-°dONLNd’ˆ&)/FileName°dONLNdfiˆAõ)?FileName in data handle°dONLNdˆ ('6†°dONLNd¯. n)TextIsPostScript°dONLNd    ç ú)_194°dONLNd
  6520. “ ◊)E0°dONLNd )0NIL°dONLNdA  )?$QuickDraw text is sent as PostScript°dONLNd8
  6521. (16†°dONLNd:
  6522. .Z)
  6523. ResourcePS°dONLNdE
  6524. çú)_195°dONLNdI
  6525. “◊)E8°dONLNdK
  6526. 9)0
  6527. Type/ID/Index°dONLNdY
  6528. A∫)?"PostScript data in a resource file°dONLNd}.l(;L
  6529. PSBeginNoSave°dONLNdãçú)_196°dONLNdè“◊)E0°dONLNdë)0NIL°dONLNdïA≠)?Set driver state to PostScript°dONLNd¥)(E6#°dONLNd∂.)a) SetGrayLevel°dONLNd√ç)ú)_197°dONLNd«“)◊)E4°dONLNd…))0Fixed°dONLNdœA)Ñ)?Call PostScript’s ,
  6530. Courier°dONLNd·Ñ)ß)Csetgray°dONLNdËß)…)#     operator°dONLNdÛ2.=^(YL RotateBegin°dONLNdˇ2ç=ú)_200°dONLNd2“=◊)E4°dONLNd2=))0    TRotation°dONLNd2A=Ü)?Begin rotated port°dONLNd#<.GU(cL    RotateEnd°dONLNd-<çGú)_201°dONLNd1<“G◊)E0°dONLNd3<G)0NIL°dONLNd7<AGp)? End rotation°dONLNdEF.Q`(mL RotateCenter°dONLNdRFçQú)_202°dONLNdVF“Q◊)E8°dONLNdXFQ)0Center°dONLNd_FAQ¶)?Offset to center of rotation°dONLNd|Ze(Å6#°dONLNd~Z.ef)
  6531. FormsPrinting°dONLNdåZçeú)_210°dONLNdêZ“e◊)E0°dONLNdíZe)0NIL°dONLNdñZAe“)?(Don’t clear print buffer after each page°dONLNdødo(ã6#°dONLNd¡d.ot)EndFormsPrinting°dONLNd“dçoú)_211°dONLNd÷d“o◊)E0°dONLNdÿdo)0NIL°dONLNd‹dAoŒ)?$End forms printing after PrClosePage
  6532. °dONLNd    nz¸(ñ6&______________________________________°dONLNd    (zÜ* †
  6533. °dONLNd    *z*Ü¢)These comments are obsolete.
  6534. °dONLNd    GÜí(Æ6#
  6535. °dONLNd    IÜ*íΔ)#These comments are not recommended. ¡4¡˘(÷62) of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇR◊#ˇ ˇˇˇˇ#◊ 
  6536. IR,Times
  6537. .+Z-Developer Support Center(-Ê October 1992 /X/
  6538. °dONLNd5<A¢(]ZLMost of the comments in Table 1 were designed specifically for the original °dONLNdL5¢A˛(]¿LaserWriter driver.°dONLNd`A<Mí(iZIn fact, the term °dONLNdrAíM )V LaserWriter°dONLNd}A M∏)81 has been (and often still is) used in the sense °dONLNdÆA∏M˛)Óof “PostScript°dONLNdΩM<YJ(uZ4printer,” and the LaserWriter driver is known to be °dONLNdÒMJY˛(uh#basically a QuickDraw-to-PostScript°dONLNdY<e|(ÅZ<translator. Meanwhile, however, QuickDraw-based LaserWriter °dONLNdQY|e˛(Åömodels came out, so we°dONLNdhe<q≤(çZshould start being more °dONLNdÄe≤q˛)vBcareful in our terminology. This is why we insist on talking about°dONLNd√q<}◊(ôZWPostScript drivers or PostScript printers when a picture comment applies to PostScript.°dONLNdâ<ïó*QuickDraw printer °dONLNd-âóï˛)[Fdrivers may implement their own picture comments, or some of the above°dONLNdtï<°v(ΩZ
  6539. comments, °dONLNd~ïv°˛):Pin order to provide additional capabilities. Certain third-party printer drivers°dONLNdœ¢<Æt( Z
  6540. implement °dONLNdŸ¢tÆk)8.text rotation, for example, by supporting the ,
  6541. Courier°dONLNd°k≠˛)˜TextBegin/TextCenter/°dONLNdÆ<∫m(◊ZTextEnd°dONLNd$Ømª«)1 picture comments.°dONLNd7«<”ø(ÔZApple’s QuickDraw printer °dONLNdQ«ø”˛)ÉBdriver for the LaserWriter SC supports the following three picture°dONLNdî”<flo(˚Z    comments:
  6542.     °dONLNdüÎRˆâ+
  6543. LineLayoutOff°dONLNd≠αˆ¿)_155°dONLNd±Îˆˆ˚)E0°dONLNd≥Î&ˆ4)0NIL°dONLNd∑ÎnˆÂ)H Turn LaserWriter line layout off°dONLNdŸıRà(p LineLayoutOn°dONLNdÊı±¿)_156°dONLNdÍıˆ˚)E0°dONLNdÏı&4)0NIL°dONLNdın‰)HTurn LaserWriter line layout on°dONLNdˇR
  6544. Ü(&p SetLineWidth°dONLNdˇ±
  6545. ¿)_182°dONLNd"ˇˆ
  6546. ˚)E4°dONLNd$ˇ&
  6547. ;)0Point°dONLNd*ˇn
  6548. –)HSet fractional line widths.
  6549. °dONLNdF<!Ò(=Z"The ImageWriter LQ driver and the °dONLNdhÒ!˛)µ7first versions of the StyleWriter driver (prior to 7.2)°dONLNd†"<.ç(JZimplement the °dONLNdÆ!ç-Ë)Q
  6550. LineLayoutOff°dONLNdª"Ë. )[ and °dONLNd¿! -_)# LineLayoutOn°dONLNdÃ"_.Œ)T picture comments. °dONLNdfl"Œ.˛)oEven the°dONLNdË.<:(VZ.ImageWriter driver reacts to picture comments:
  6551.     °dONLNdFRQü+BitMapThinningOff°dONLNd*F±Q≈)_1000°dONLNd/FˆQ˚)E0°dONLNd1F&Q4)0NIL°dONLNd5FnQÂ)HTurn off hi-res bitmap thinning°dONLNdVPR[û(wpBitMapThinningOn°dONLNdgP±[≈)_1001°dONLNdlPˆ[˚)E0°dONLNdnP&[4)0NIL°dONLNdrPn[‰)HTurn on hi-res bitmap thinning
  6552. °dONLNdëf<r*(éZ1The ImageWriter driver does the same toggling of °dONLNd¬f*r˛)Ó,the “bitmap thinning” of fat bitmaps in Best°dONLNdÔs<^(õZmode, °dONLNdıs^ )"when it encounters a °dONLNd
  6553. r ~    )l    TextBegin°dONLNds    )? or °dONLNdr~N)TextEnd°dONLNdsNÒ)1 comment (undocumented feature°dONLNd<sÒ˛)£—°dONLNd=<ã¶(ßZInever mind!). The ImageWriter LQ driver handles these comments similarly.°dONLNdáó<£Ô*YThe current StyleWriter driver (version 7.2.2) and the personal LaserWriter LS driver do °dONLNd‡óÔ£˛(ø
  6554. not°dONLNd‰£<ØÁ(ÀZ$support any picture comments at all.°dONLNd
  6555. ª<«¶*The point of all this is:°dONLNd$”Öfl¥+I4It is impossible to determine which picture comments°dONLNdYfl∞Îä++ &are supported by which printer driver.°dONLNdĘ<—(ZUIn other words, your application should never assume a particular picture comment is °dONLNd’˜—˛(Ô
  6556. available,°dONLNd‡<O(+Zbut °dONLNd‰O˛)Vyour application also should not defeat the device-independent design of the Macintosh°dONLNd;<V(7Z>printing architecture by writing printer driver–specific code!°dONLNd{(<4®*Of course, you know (°dONLNdê(®4˘)lInside Macintosh°dONLNd†(˘4ä)Q Volume II, page 152) that the °dONLNdø(ä4€)ëhigh byte of the °dONLNd–'€3˛)QprStl°dONLNd÷5<A@(]Z.°dONLNd◊4@@\)wDev°dONLNd€5\AÑ)
  6557.  field of °dONLNdÂ5ÑA˛)(Sthe print record identifies a printer driver species, and that a value of $03 tells°dONLNd    9A<MÈ(iZ]you the printer driver belongs to the PostScript LaserWriter driver ancestry. As a matter of °dONLNd    ñAÈM˛(ifact,°dONLNd    úM<Y¨(uZPmany applications use this information to achieve special printing features not °dONLNd    ÏM¨Y˛(u available through°dONLNd    ˛Y<eŒ(ÅZthe Printing Manager interface.°dONLNd
  6558. q<}R*6And, of course, you also know that we don’t like this °dONLNd
  6559. TqR}˛(ôp!idea. One reason is future system°dONLNd
  6560. v}<âî(•ZLsoftware may allow spool files to be redirected to a printer other than the °dONLNd
  6561. ¬}îâ˛(•≤one chosen when you°dONLNd
  6562. ÷â<ïfi(±ZUsent your printing instructions (including picture comments). Another reason is that °dONLNd +âfiï˛(±¸picture ¡X¡
  6563. (÷Z&QD 10 - Picture Comments—The Real Deal(÷ˇ3) of 26(ÏZM.QD.PictCommentsˇÓ◊#ˇ ˇˇˇˇ#◊ 
  6564. IR,Times
  6565. .+6-Macintosh Technical Notes /4/˘
  6566. °dONLNd)´*Rcomments usually are included in PICTs; documents containing such pictures should °dONLNdR´)⁄(E…
  6567. print with°dONLNd])5b(Q6optimal results °dONLNdm)b5⁄)JJon any printer configuration. And, finally, you never know what the future°dONLNd∏5AH(]6
  6568. holds for °dONLNd¬5HA⁄)0Nyou, in terms of new printing devices or new printer drivers—or a new printing°dONLNdAMR(i6
  6569. architecture!°dONLNdYez*Instead, if a picture °dONLNd5Yze⁄)bG(i.e., a sequence of imaging instructions) contains picture comments to°dONLNd}eq®(ç6enhance the output on devices °dONLNdõe®q⁄)ê>that support them, it should also contain a standard QuickDraw°dONLNd⁄q}w(ô6Mrepresentation as a fallback solution, in case the rendering device does not °dONLNd'qw}⁄(ôïrecognize the picture°dONLNd=}â~(•6Bcomments. The design and implementation of these picture comments °dONLNd}~â⁄(•úshould incorporate°dONLNdíâï¶(±6Uconventions to make this cohabitation of two representations in one picture possible.
  6570. °dONLNdË≠º4*'(Cohabitation of QuickDraw and PostScript
  6571. °dONLNd»‘∫*Device-Independent Pictures°dONLNd-·Ì„*'We can think of the Printing Manager’s ,
  6572. Courier°dONLNdT‡„Ï))À
  6573. PrOpenPage°dONLNd^·)ÌD)F and °dONLNdc‡DÏë) PrClosePage°dONLNdn·ëÌ∞)M calls °dONLNdu·∞Ì⁄)as being°dONLNd~Ó˙h(6analogous to the °dONLNdèÌh˘µ)P OpenPicture°dONLNdöÓµ˙∏)M °dONLNdõÓ∏˙Õ)and °dONLNdüÌÕ˘!) ClosePicture°dONLNd´Ó!˙⁄)T% calls (which, by the way, reminds us°dONLNd—˚c(#6to never call °dONLNdfl˙c∞)K OpenPicture°dONLNdÍ˚∞Á)M     between °dONLNdÛ˙Á-)7
  6574. PrOpenPage°dONLNd˝˚-N)F and °dONLNd˙Nõ)! PrClosePage°dONLNd
  6575. ˚õΩ)M; see °dONLNd˚Ω⁄)"Inside°dONLNdI(/6    Macintosh°dONLNd#I±)1J Volume II, page 160). In both cases, a stream of imaging instructions is °dONLNdm±⁄(/œrecorded°dONLNdv¥(;6 for deferred rendering. We want °dONLNdñ¥⁄)ú<to create pictures that include both QuickDraw and optimized°dONLNd”+2(G6>PostScript representations so that we obtain the best results °dONLNd2+⁄(GP"in all circumstances. We must take°dONLNd4+7–(S6'special care for third-party QuickDraw °dONLNd[+–7⁄)∏8printer drivers that support picture comments originally°dONLNdî7C«(_6%intended for PostScript devices only.°dONLNd∫O[•*Let’s start with the easy ones.°dONLNd⁄htú*The two picture comments °dONLNdÛgús)ÑPostScriptBegin°dONLNdht)i and °dONLNdgsy)
  6576. PostScriptEnd°dONLNdhyt†)[     clearly °dONLNdh†t⁄)' suggest that°dONLNd*tÄ–(ú6^any imaging instructions in between are intended exclusively for PostScript printing devices. °dONLNdàt–Ä⁄(úÓIn°dONLNdãÅç@(©6    the case °dONLNdîÅ@ç3)(4of the PostScript LaserWriter driver, the effect of °dONLNd»Ä3åú)ÛPostScriptBegin°dONLNd◊Åúç⁄)i is to disable°dONLNdÊéöÖ(∂6all bottlenecks except °dONLNd˝çÖô“)m commentProc°dONLNdé“ö€)M, °dONLNd
  6577. ç€ô!)    
  6578. txMeasProc°dONLNdé!ö*)F, °dONLNdç*ôp)    
  6579. getPicProc°dONLNd épöy)F, °dONLNd"éyöê)    and °dONLNd&çêô÷)
  6580. putPicProc°dONLNd0é÷ö⁄)F.°dONLNd2ö¶¸(¬6.This means that QuickDraw’s text, line, shape °dONLNd`ö¸¶⁄)‰*(Rects, RoundRects, Ovals, Arcs, Polygons)°dONLNdã¶≤R(Œ6?and bitmap drawing calls don’t have any effect in the printing °dONLNd ¶R≤⁄(ŒpgrafPort when enclosed by°dONLNd‰≤æÅ(€6PostScriptBegin°dONLNdÛ≥Åøá)i °dONLNdÙ≥áøü)and °dONLNd¯≤üæ˙)
  6581. PostScriptEnd°dONLNd≥˙ø⁄)[,. Instead, the PostScript LaserWriter driver°dONLNd2¿Ã≤(Ë6expects to receive the imaging °dONLNdQ¿≤Ãj)ö%instructions as data enclosed in the °dONLNdvøjÀ⁄)∏PostScriptHandle°dONLNdáÃÿ£(Ù6Pcomment. This way, both the PostScript and QuickDraw representation can coexist °dONLNd◊ãÿ⁄(Ù¡ in the same°dONLNd„ÿ‰;(6picture °dONLNdÎÿ;‰⁄)#Wwithout conflict. As a consequence, non-PostScript printer drivers, unable to interpret°dONLNd    C‰c( 6Dgeneral PostScript text, must not imitate this behavior of ignoring °dONLNd    á‰c⁄( ÅQuickDraw instructions,°dONLNd    üÒ˝›(6'even when they implement other picture °dONLNd    ΔÒ›˝<)≈comments such as °dONLNd    ◊<¸{)_    TextBegin°dONLNd    ‡Ò{˝ñ)? and °dONLNd    Âñ¸«)TextEnd°dONLNd    ÏÒ«˝⁄)1 for°dONLNd    Ò˝    ©(%6text rotation. Otherwise, they °dONLNd
  6582. ˝©    ⁄)ë:would miss the QuickDraw representation of some PostScript°dONLNd
  6583. K    B(16imaging.°dONLNd
  6584. T".h*The text rotation °dONLNd
  6585. f"h.ƒ)Ppicture comments (°dONLNd
  6586. x!ƒ-)\    TextBegin°dONLNd
  6587. Å". )?, °dONLNd
  6588. É! -Q)
  6589. TextCenter°dONLNd
  6590. ç"Q.Y)F, °dONLNd
  6591. è!Y-ä)TextEnd°dONLNd
  6592. ñ"ä.⁄)1) silently include°dONLNd
  6593. ©.:J(V6Athe assumption that a printer driver that supports these comments°dONLNd
  6594. ÎGS*1a. ignores the QuickDraw clipping region between °dONLNd FRG)    TextBegin°dONLNd %GGS^)? and °dONLNd *F^Rè)TextEnd°dONLNd 2T`ï(|6b. ignores the QuickDraw °dONLNd KSï_Õ)}CopyBits°dONLNd STÕ`&)8 instruction within °dONLNd gS&_ù)YTextBegin/TextEnd°dONLNd ylx0(î6This °dONLNd ~l0x⁄)[way, a bitmap representation of the rotated text can be included in the picture. It will be°dONLNd ⁄yÖ\(°6
  6595. used only if °dONLNd Áy\Öq)Dthe °dONLNd ÎxqÑË)TextBegin/TextEnd°dONLNd ¸yËÖ⁄)w, comments are not supported. Conversely, the°dONLNd )ÖëI(≠6>QuickDraw commands required to draw the text to be rotated by °dONLNd gÖIë⁄(≠gthe printer driver are “hidden” ¡4¡˘
  6596. (÷64) of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇ◊#ˇ ˇˇˇˇ#◊ 
  6597. IR,Times
  6598. .+Z-Developer Support Center(-Ê October 1992 /X/
  6599. °dONLNd<)€(EZfrom QuickDraw by setting the °dONLNd€)˛)ü8clipping region to empty, which is ignored by the driver°dONLNdW)<5∑(QZsupporting the comments.°dONLNdpA<M*-The polygon picture comments provide another °dONLNdùAM˛)‚/solution to the problem, in form of the special°dONLNdÕN<Zj(vZcomment ,
  6600. Courier°dONLNd’MjY∞).
  6601. PolyIgnore°dONLNdflN∞Z0)F. It allows one to include a °dONLNd¸N0Z˛)Ä(QuickDraw representation of the smoothed°dONLNd%Z<fl(ÇZ    polygon, °dONLNd.Zlf˛)0Mignored by a driver that supports polygon smoothing (such as via PostScript’s°dONLNd|f<r_(èZcurve°dONLNdÅg_sd)# °dONLNdÇgds˛)Moperator). And for filled polygons, QuickDraw’s region concept works around a°dONLNd–s<ó(õZHconflict of who owns which polygon (see sample code later in this Note).°dONLNdã<óÀ*SSome picture comments (such as the line layout comments) do not require a fallback °dONLNdlãÀó˛(≥È solution in°dONLNdxó<£'(øZ4case they are not supported by a printer driver; or °dONLNd¨ó'£˛)Î/the feature, if absent, is not a big loss (such°dONLNd‹§<∞J(ÃZas °dONLNdfl£JØû) SetLineWidth°dONLNdΧû∞¶)T, °dONLNḑ¶∞˛)Dprovided you use it only for widths smaller than one 72-dot-per-inch°dONLNd2∞<ºÆ(ÿZ(dpi) QuickDraw pixel).°dONLNdK…<’*But for the picture comments °dONLNdh»‘É)¥DashedLine/DashedStop°dONLNd}…É’™)ì and     °dONLNdÇ»™‘˛)' RotateBegin/°dONLNdè’<·÷(˛ZRotateCenter/RotateEnd°dONLNd•÷÷‚‘)ö5, there is no general solution to the “cohabitation” °dONLNd⁄÷‘‚˛)˛problem;°dONLNd„‚<ÓB(
  6602. Z8and we are distressed about it. It is obvious that they °dONLNd‚BÓ˛(
  6603. `%have been defined with the PostScript°dONLNdAÓ<˙≈(ZLaserWriter driver in mind, °dONLNd]Ó≈˙˛)â?without anticipating a future furnished by some 150 third-party°dONLNdù˙<´("ZPprinter drivers. The only way to include both representations in these cases is °dONLNdÌ˙´˛("…indeed to assume°dONLNd˛<x(.Z
  6604. that only     °dONLNdx˛)<BPostScript drivers will support the picture comment, such that the°dONLNdK<•(;ZPostScriptBegin°dONLNdZ•©)i °dONLNd[©ø)and °dONLNd_ø)
  6605. PostScriptEnd°dONLNdl˛)[* comments can be used to “comment out” the°dONLNdó<+ª(GZQuickDraw representation.°dONLNd±7<CÜ*Even under the °dONLNd¿7ÜC˛)JMabove assumption, we still need a trick to prevent the QuickDraw calls within°dONLNdC<O≥(kZHthe scope of the picture comments from showing up when the comments are °dONLNdVC≥O˛(k—not recognized.°dONLNdfO<[˝(wZ(Fortunately, early Macintosh developers °dONLNdéO˝[˛)¡5discovered a QuickDraw feature that, unintentionally,°dONLNdƒ\<h](ÑZsolves °dONLNdÀ\]h>)!,the problem. Passing the “magic” mode 23 to °dONLNd˜[>go)·PenMode°dONLNd˛\oh˛)1 inhibits QuickDraw’s normal°dONLNdh<tì(êZdrawing, but still °dONLNd.hìt˛)WIlets the LaserWriter driver see the drawing instructions come through the°dONLNdxt<Ä»(úZTbottlenecks, so that it can translate them into PostScript. Note that this pen mode °dONLNdÃt»Ä˛(úÊ
  6606. always has°dONLNd◊Ä<å£(®ZIbeen undocumented, and that using it was considered a compatibility risk °dONLNd Ä£å˛(®¡and frowned upon°dONLNd1å<ò∑(¥ZOfor some time. Given the current state of affairs, however, there is no reason °dONLNdÄå∑ò˛(¥’
  6607. anymore to be°dONLNdéò<§è(¿Zparanoid about it.°dONLNd°≥<øV*-Keeping QuickDraw and PostScript Synchronized°dONLNdœÀ<◊œ*There are two situations, in °dONLNdÏÀœ◊˛)ì8the context of picture comments, where the design of the°dONLNd    %◊<„Ó(ˇZ[PostScript LaserWriter driver requires special precautions from the application programmer.°dONLNd    Ç<¸*+First, certain QuickDraw instructions like °dONLNd    ≠Ô˚#)ÀMove°dONLNd    ±#¸+), °dONLNd    ≥Ô+˚U)MoveTo°dONLNd    πU¸^)*, °dONLNd    ªÔ^˚à)    PenPat°dONLNd    ¡à¸ß)*, and °dONLNd    «Ôß˚ÿ)PenSize°dONLNd    Œÿ¸˛)1 change°dONLNd    ÷˝<    /(%Z5the state of the grafPort, without going through the °dONLNd
  6608. ¸/`)ÛQDProcs°dONLNd
  6609. ˝`    —)1 bottleneck procedures. °dONLNd
  6610. *˝—    ˙)qA Macin°dONLNd
  6611. 1˝˙    ˛))-°dONLNd
  6612. 2    <ˇ(1Z(tosh printer driver takes these changes °dONLNd
  6613. Z    ˇ˛)√3into account only at the time it executes an actual°dONLNd
  6614. é<"z(>ZAdrawing instruction. Remember, the printer driver hooks into the °dONLNd
  6615. œz!´(>òQDProcs°dONLNd
  6616. ÷´"˛)1 to get execution°dONLNd
  6617. Ë#</S(KZtime °dONLNd
  6618. Ì#S/@)0and only “sees” instructions coming through the °dONLNd "@.q)ÌQDProcs°dONLNd $#q/Ú)1. Nothing is wrong with it°dONLNd >#Ú/˛)Å—°dONLNd ?/<;Ì(WZ%unless PostScript code is woven into °dONLNd d/Ì;˛)±7the graphics instructions by means of picture comments.°dONLNd ú;<G´(cZ(Note that PostScript °dONLNd ≤;´G˛)o?code may be generated transparently when the LaserWriter driver°dONLNd ÚG<SÙ(oZ\encounters certain picture comments.) If the PostScript code assumes that the current state °dONLNd NGÙS˛(oof°dONLNd QS<_â({ZDthe grafPort corresponds to what you expect it to be, then you have °dONLNd ïSâ_˛({ßto flush the state of the°dONLNd Ø_<ké(áZIgrafPort explicitly before inserting the PostScript code. This is easier °dONLNd ¯_ék˛(á¨than it sounds; just do°dONLNd
  6619. l<x(îZ,something inoffensive that goes through the °dONLNd
  6620. <kwä)fiQDProcs.lineProc°dONLNd
  6621. Lläx˛)p bottleneck, like in the°dONLNd
  6622. ex<ÑΩ(†Zfollowing utility procedure: ¡X¡
  6623. *6&QD 10 - Picture Comments—The Real Deal(÷ˇ5) of 26(ÏZM.QD.PictCommentsˇö◊#ˇ ˇˇˇˇ#◊ 
  6624. IR,Times
  6625. .+6-Macintosh Technical Notes /4/˘,
  6626. Courier
  6627.     °dONLNd(©*PROCEDURE FlushGrafPortState;°dONLNd'2ä*
  6628. J{ This routine causes the state of the Printing Manager's grafPort to be }°dONLNdi1<ä*
  6629. J{ flushed out to the LaserWriter, by making a dummy call through the     }°dONLNd¥;Fä*
  6630. J{ QDProcs.lineProc bottleneck. Pen size and pen location are preserved.  }°dONLNdˇOZ6*   VAR°dONLNdYdê*
  6631.       penInfo: PenState;°dONLNdmx@*   BEGIN°dONLNd(wÇè*
  6632. K      GetPenState(penInfo);                              { Save pen size. }°dONLNdtÅåè*
  6633. K      PenSize(0,0);                                  { Make it invisible. }°dONLNd¿ãñè*
  6634. K      Line(0,0);                           { Go through QDProcs.lineProc. }°dONLNd ï†è*
  6635. K      PenSize(penInfo.pnSize.h, penInfo.pnSize.v);    { Restore pen size. }°dONLNdXü™;*
  6636.    END;
  6637. °dONLNd`µ¡ï*Another unwanted effect °dONLNdxµï¡⁄)}Cis related to the PostScript LaserWriter driver’s multiple internal°dONLNdº¡Õ‰(È6(buffering of generated PostScript code. °dONLNd‰¡‰Õ⁄)Ã.The PostScript code generated for text drawing°dONLNdÕŸ§(ı6instructions (which usually °dONLNd/Õ§Ÿ⁄)å:involves font queries and, sometimes, font downloading) is°dONLNdjŸÂ/(69buffered independently from the PostScript code inserted °dONLNd£Ÿ/Â⁄(M by means of picture comments. In°dONLNdƒÂÒ÷(
  6638. 6*certain cases, this results in apparently °dONLNdÓÂ÷Ò⁄)æ4nonsequential execution of drawing instructions, and°dONLNd#Ò˝)(68may affect clipping regions or may have side effects on °dONLNd[Ò)˝⁄(G#the PostScript code you included in°dONLNd˝    È(%6*picture comments. In order to synchronize °dONLNd©˝È    ⁄)—/the sequence of QuickDraw instructions with the°dONLNdŸ    k(16Hgeneration of PostScript code, you need to call the following procedure:
  6639.     °dONLNd"!,≥*PROCEDURE FlushPostScriptState;°dONLNdB+6Ö*
  6640. I{ This routine flushes the buffer maintained by the LaserWriter driver. }°dONLNdå5@Ö*
  6641. I{ All PostScript, generated either by the app or by the LaserWriter     }°dONLNd÷?JÖ*
  6642. I{ driver, will be sent to the device.                                   }°dONLNd IT@*
  6643.    BEGIN°dONLNd)S^Í*
  6644. *      PicComment(PostScriptBegin, 0, NIL);°dONLNdT]h‡*
  6645. (      PicComment(PostScriptEnd, 0, NIL);°dONLNd}gr;*
  6646.    END;
  6647. °dONLNdÖ}â“*'In the following discussion of picture °dONLNd¨}“â⁄)∫6comments, we’ll refer to these two utility routines as°dONLNd„âïQ(±6 appropriate.
  6648. °dONLNd≠ºs*'
  6649. Text Rotation
  6650. °dONLNd˛…’W*    Comments:°dONLNd»`‘ü)H    TextBegin°dONLNd…ü’¶)?, °dONLNd»¶‘Ï)
  6651. TextCenter°dONLNd…Ï’Û)F, °dONLNd»Û‘$)TextEnd°dONLNd'·ÌÑ(    6These comments give °dONLNd;·ÑÌ⁄)lIaccess to PostScript’s capabilities of rotating, flipping, and justifying°dONLNdÖÌ˘∞(6Ttext. They are intended for applications likely to be used with PostScript printers °dONLNdŸÌ∞˘⁄(Œ(such as°dONLNd‚˘=(!67desktop publishing and advanced drawing applications), °dONLNd˘=⁄(![but which don’t want to use°dONLNd5X(-6EPostScript explicitly. Note that some non-PostScript printer drivers °dONLNdzX⁄(-vsupport these comments as°dONLNdîÏ(96,well. For situations where the comments are °dONLNd¿Ï⁄)‘/not supported (such as the QuickDraw screen, or°dONLNd)π(E6!most QuickDraw printer drivers), °dONLNd    π)g)°"you must provide a bitmap represen°dONLNd    4g)⁄)Ætation of the rotated text°dONLNd    O)5g(Q6as an alternative.°dONLNd    cAM…*%Let’s look at sample code right away.
  6652.     °dONLNd    âYd£*OUSES  PicComments;  { See Appendix; defines constants for just and flip and   }°dONLNd    Ÿcn£*
  6653. O                    { the structures referred to by TTxtPicHdl and TCenterHdl.} ¡4¡˘
  6654. *L6) of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇº◊#ˇ ˇˇˇˇ#◊ 
  6655. IR,Times
  6656. .+Z-Developer Support Center(-Ê October 1992 /X/,
  6657. Courier
  6658.     °dONLNd<(1(DZ1PROCEDURE QDStringRotation(s: Str255; ctr: Point;°dONLNd3'<2ö*
  6659. F                           just, flip: Integer; rot: Fixed); EXTERNAL;°dONLNdz1<<«*
  6660. O{ This routine should generate a bitmap of the rotated and flipped text       }°dONLNd ;<F«*
  6661. O{ and use CopyBits to draw it to the grafPort. Left as an exercise ...        }°dONLNdO<Z¬*NPROCEDURE DrawXString(s: Str255; ctr: Point; just, flip: Integer; rot: Fixed);°dONLNdiY<d«*
  6662. O{ Draws the string s rotated by rot degrees around the current point, offset  }°dONLNdπc<n«*
  6663. O{ by ctr, justifying and flipping according to the just and flip parameters.  }°dONLNd    m<x«*
  6664. O{ If the printer driver supports the TextBegin, TextCenter, and TextEnd       }°dONLNdYw<Ç«*
  6665. O{ picture comments, it rotates the text at device resolution; otherwise, the  }°dONLNd©Å<å«*
  6666. O{ external procedure QDStringRotation is called to image the rotated string.  }°dONLNd˘ã<ñÊ*
  6667. "{ The pen position is preserved. }°dONLNdü<™Z*   VAR°dONLNd#©<¥ö*
  6668. F      hT: TTxtPicHdl;     { Defined in PicComments.p - see Appendix. }°dONLNdj≥<æ·*
  6669. !      hC: TCenterHdl;     { –"– }°dONLNdåΩ<»•*
  6670.       zeroRect: Rect;°dONLNd¢«<“å*
  6671.       pt: Point;°dONLNd≥—<‹π*
  6672.       oldClip: RgnHandle;°dONLNdÕÂ<d*   BEGIN°dONLNd÷Ô<˙;*
  6673. 3      GetPen(pt);  { to preserve the pen position }°dONLNd
  6674. <J*6      hT := TTxtPicHdl(NewHandle(SizeOf(TTxtPicRec)));°dONLNdA
  6675. <J*
  6676. 6      hC := TCenterHdl(NewHandle(SizeOf(TCenterRec)));°dONLNdx<"∏*
  6677. L      { No error handling: if these fail, we are in deep trouble anyway ...}°dONLNd≈!<,¥*
  6678.       WITH hT^^ DO BEGIN°dONLNdfi+<6√*
  6679.          tJus      := just;°dONLNd˙5<@√*
  6680.          tFlip     := flip;°dONLNd?<JÆ*
  6681. J         tAngle    := - FixRound(rot); { I like counterclockwise better. }°dONLNdbI<Tı*
  6682. %         tLine     := 0; { reserved }°dONLNdàS<^Ü*
  6683. B         tCmnt     := 0; { used internally by the printer driver }°dONLNdÀ]<h“*
  6684.          tAngleFixed := - rot;°dONLNdÍg<rn*
  6685.  
  6686.       END;°dONLNdıq<|‹*
  6687.        hC^^.y := Long2Fix(ctr.v);°dONLNd{<Ü‹*
  6688.        hC^^.x := Long2Fix(ctr.h);°dONLNd7è<ö^*:      PicComment(TextBegin,SizeOf(TTxtPicRec),Handle(hT));°dONLNdrô<§c*
  6689. ;      PicComment(TextCenter,SizeOf(TCenterRec),Handle(hC));°dONLNdÆ£<Ƨ*
  6690. H      { PostScript graphics state now has rotated/flipped coordinates. }°dONLNd˜∑<¬¥*      oldClip := NewRgn;°dONLNd¡<ÃØ*
  6691.       GetClip(oldClip);°dONLNd(À<÷‹*
  6692.        SetRect(zeroRect,0,0,0,0);°dONLNdI’<‡∏*
  6693. L      ClipRect(zeroRect);  { Hides the following DrawString from QuickDraw }°dONLNdñfl<Íw*
  6694. ?      DrawString(s); { in the rotated PostScript environment. }°dONLNd÷È<ÙÊ*
  6695. "      ClipRect(oldClip^^.rgnBBox);°dONLNd˘˝<≥*K      { Now the "fallback" bitmap representation; see the comments above  }°dONLNdE<w*
  6696. ?      { at the declaration of the QDStringRotation procedure. }°dONLNdÖ<,*
  6697. 0      QDStringRotation(s, ctr, just, flip, rot);°dONLNd∂%<0«*O      PicComment(TextEnd,0,NIL); { Set environment back to the original state }°dONLNd    9<D◊*      DisposHandle(Handle(hT));°dONLNd    &C<N◊*
  6698.       DisposHandle(Handle(hC));°dONLNd    FW<b^*:      MoveTo(pt.h,pt.v);  { to preserve the pen position }°dONLNd    Åa<l_*
  6699.    END;
  6700. °dONLNd    âw<É∑*The preceding discussion °dONLNd    ¢w∑ɲ){Aabout including both QuickDraw and PostScript representations and°dONLNd    ‰É<è¡(´ZQthe comments included in the source code say it all: The conventions tied to the °dONLNd
  6701. 5É¡è˛(´fl usage of the ¡X¡
  6702. (÷Z&QD 10 - Picture Comments—The Real Deal(÷ˇ7) of 26(ÏZM.QD.PictCommentsˇ,◊#ˇ ˇˇˇˇ#◊ 
  6703. IR,Times
  6704. .+6-Macintosh Technical Notes /4/˘,
  6705. Courier
  6706. °dONLNd)W*    TextBegin°dONLNd    W*n)? and °dONLNdn)ü)TextEnd°dONLNdü*µ)1; picture comments allow you to take advantage of a printer °dONLNdPµ*⁄(F”driver’s°dONLNdY*6˙(R61implementation of high-resolution text rotation, °dONLNdä*˙6⁄)‚.while including a bitmapped representation for°dONLNdπ6B“(^6%where the comments are not supported.°dONLNdflNZô*Some Additional Hints°dONLNdıfr*•°dONLNd˜f%râ)
  6707. HBecause of QuickDraw’s orientation of the vertical coordinate axis, the °dONLNd?fâr⁄(éßrotation angle is°dONLNdQr%~£(öCLmeasured clockwise. Nothing prevents us from using the negative angle if we °dONLNdùr£~⁄(ö¡ are used to°dONLNd©~%ä¡(¶C!the counterclockwise orientation.°dONLNdÀó£(ø6•°dONLNdÕó%£Û)
  6708. +The angle is measured in degrees (0..360), °dONLNd¯óÛ£C)Œand passed as a °dONLNdñC¢f)PFixed°dONLNd
  6709. óf£⁄)# type number (that is, if°dONLNd'§%∞V(ÃC taken as a °dONLNd2£VØá)1LongInt°dONLNd9§á∞™)1 value, °dONLNdA§™∞⁄)#?you have to divide it by 65536 to obtain the angle in degrees).°dONLNdű%Ω:(ŸCFor °dONLNdÖ±:Ω!)0integer angles, it is possible to use a reduced °dONLNdµ∞!ºg)Á
  6710. TTxtPicRec°dONLNdø±gΩ⁄)F structure that does not°dONLNdÿæ% w(ÊC contain the °dONLNd‰Ωw…Ø)RtRotFrac°dONLNdÏæØ ≈)8* field. The PostScript LaserWriter driver °dONLNdæ≈ ⁄(Ê„uses°dONLNd %÷ú(ÛCGetHandleSize(hT)°dONLNd,Àú◊Â)w to determine °dONLNd:ÀÂ◊⁄)I/whether it must use the fractional angle in the°dONLNdj◊%„](CtRotFrac°dONLNdrÿ]‰˘)8# field. To be safe, always set the °dONLNdï◊˘„)útRot°dONLNdôÿ‰<)
  6711.  field to °dONLNd£◊<„∫)'FixRound(tRotFrac)°dONLNdµÿ∫‰Ω)~ °dONLNd∂ÿΩ‰⁄)if you°dONLNdΩÂ%Òä(
  6712. Cgo with the extended °dONLNd“‰ä–)e
  6713. TTxtPicRec°dONLNd‹Â–Ò )F (as we do here).°dONLNdÓ˛
  6714. (&6•°dONLNd˛%
  6715. P)
  6716. ?It is convenient that clipping regions are ignored between the °dONLNd/˝P    è(&n    TextBegin°dONLNd8˛è
  6717. ì)? °dONLNd9˛ì
  6718. ©)and °dONLNd=˝©    ⁄)TextEnd°dONLNdE %ß(3Cpicture comments, because °dONLNd_ ß*)Çit allows us to clip out the °dONLNd|
  6719. *p)É
  6720. DrawString°dONLNdÜ p⁄)F on printers that don’t°dONLNdû%#œ(?CXsupport these comments. Unfortunately, this also means that text rotated this way can’t °dONLNdˆœ#⁄(?Ìbe°dONLNd˘#%/◊(KCbclipped. If clipping of rotated text is required, you’ll have to do it entirely within PostScript.°dONLNd\;G(c6•°dONLNd^;%GM)
  6721. @Due to the LaserWriter driver’s internal buffering of generated °dONLNdû;MG⁄(ckPostScript code, the effect of°dONLNdΩG%SL(oC>ignoring clip regions may be propagated to preceding sections °dONLNd˚GLS⁄(ojof your drawing instructions.°dONLNdT%`£(|CWe recommend calling °dONLNd.T£`∫)~the °dONLNd2S∫_F)FlushPostScriptState°dONLNdFTF`⁄)å procedure described earlier°dONLNdca%mì(âCimmediately before the °dONLNdz`ìl“)n    TextBegin°dONLNdÉa“m)?     comment.°dONLNdçzÜ(¢6•°dONLNdèz%Ü:)
  6722. The °dONLNdìy:ÖV)tJus°dONLNdózVÜé) field in the °dONLNd•yéÖ‘)8
  6723. TTxtPicRec°dONLNdØz‘Ü*)F, if different from °dONLNd√y*Öb)VtJusNone°dONLNdÀzbÜ—)8, tells the printer driver °dONLNdÊz—Ü⁄)oto°dONLNdÈÜ%í[(ÆCGmaintain either the left, right, or center point of the string without °dONLNd0Ü[í⁄(Æyrecalculating the interword°dONLNdLì%ü©(ªCand intercharacter spacing. °dONLNdhì©ü¿)ÑThe °dONLNdlí¿û¯)tJusFull°dONLNdtì¯ü⁄)80 value specifies that the original length of the°dONLNd•ü%´Ù(«C)string (on the QuickDraw screen) must be °dONLNdŒüÙ´⁄)œ.maintained. This is important when the printer°dONLNd˝´%∑?(”C=font has widths different from those of the screen font, and °dONLNd:´?∑⁄(”] when you rotate justified blocks°dONLNd[∑%√G(flCof text.°dONLNdd–‹(¯6•°dONLNdf–%‹<)
  6724. The °dONLNdjœ<€_)tFlip°dONLNdo–_‹ü)# field in the °dONLNd}œü€Â)@
  6725. TTxtPicRec°dONLNdá–‹¨)F+ specifies horizontal or vertical flipping °dONLNd≤–¨‹⁄)«    about the°dONLNdº›%Ȩ(Ccenter point specified by the °dONLNd⁄‹¨ËÚ)á
  6726. TextCenter°dONLNd‰›ÚÈ$)F     comment.°dONLNdÓˆ(6•°dONLNdˆ%:)
  6727. The °dONLNdÙı:Ä)
  6728. TextCenter°dONLNd˛ˆÄA)F* comment specifies the center of rotation °dONLNd    (ˆA⁄)¡ for any text enclosed within the°dONLNd    I%d(+C    TextBegin°dONLNd    Rd)? and °dONLNd    W∞)TextEnd°dONLNd    ^∞)1, calls, as an offset to the location of the °dONLNd    ä⁄)œcurrent point. The°dONLNd    ù%â(7CArotation is achieved by changing PostScript’s coordinate system. °dONLNd    fiâ⁄(7ß
  6729. A sequence of°dONLNd    Ï%'¥(DCDrawString – MoveTo°dONLNd    ˇ¥(3)è instructions is rotated °dONLNd
  6730. 3(ò)as a whole until °dONLNd
  6731. )ò'…)eTextEnd°dONLNd
  6732. 0…(⁄)1 is°dONLNd
  6733. 4(%4b(PC encountered.°dONLNd
  6734. AAM(i6•°dONLNd
  6735. CA%Mm)
  6736. BSome versions of double-byte Kanji systems print Kanji characters °dONLNd
  6737. ÖAmM¢(iã by calling °dONLNd
  6738. ê@¢L⁄)5CopyBits°dONLNd
  6739. ôM%Yl(uCBinstead of calling standard text drawing routines. This means the °dONLNd
  6740. €MlY⁄(uäcomments in the Text°dONLNd
  6741. Y%e…(ÅCRotation family cannot be used °dONLNd Y…e⁄)§4with these fonts. Instead, use the Graphics Rotation°dONLNd De%qˆ(çC,comment family described later in this Note. ¡4¡˘
  6742. (÷68) of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇJ◊#ˇ ˇˇˇˇ#◊ 
  6743. IR,Times
  6744. .+Z-Developer Support Center(-Ê October 1992 /X/
  6745. °dONLNd<,≈(HZLine Layout Control
  6746. °dONLNd9<E{*    Comments:,
  6747. Courier°dONLNd8ÑDÿ)H LineLayoutOn°dONLNd*9ÿEfl)T, °dONLNd,8flD:)
  6748. LineLayoutOff°dONLNd99:EA)[, °dONLNd;8AD±)ClientLineLayout°dONLNdLQ<]i(yZAWhen drawing to a printing grafPort, the selected printer driver °dONLNdçQi]˛(yádoes a lot of work “behind the°dONLNd¨]<ió(ÖZscenes” to try to °dONLNdæ]ói˛)[>maintain the infamous “What-You-See-Is-What-You-Get” (WYSIWYG)°dONLNd˝i<u∑(ëZmetaphor from the screen °dONLNdi∑u˛){Cto the paper, and generally to make the printed output look as good°dONLNdZu<ÅŸ(ùZZas possible. Depending on the target device, the printer driver, and the configuration of °dONLNd¥uŸÅ˛(ù˜fonts in°dONLNdΩÅ<ç(©Z,the system, the font you draw text with may °dONLNdÈÅç˛)”/be scaled, smoothed, remapped, or even replaced°dONLNdç<ôÅ(µZby a font built °dONLNd)çÅô˛)ESinto the printer. In nearly all cases where the device resolution of the printer is°dONLNd}ô<•(¡Z(different from QuickDraw’s “hard-coded” °dONLNd•ô•˛)…472-dpi screen resolution, the width of text rendered°dONLNd⁄•<±©(ÕZNon the printer is different from the text width on the screen. This is due to °dONLNd(•©±˛(Õ«nonproportionally°dONLNd:±<Ω (ŸZ-scaling bitmapped fonts, different character °dONLNdg± Ω˛)œ3widths after font substitution, and rounding errors°dONLNdõΩ<…‹(ÂZ"of fractional character widths on °dONLNdΩΩ‹…˛)†<the screen. The difference in the width of a line of text is°dONLNd˙…<’k(ÒZ called the °dONLNd…k’«)/line layout error°dONLNd…«’À)\.°dONLNd·<ÌÌ(    Z&The printer driver is responsible for °dONLNd>·ÌÌ˛)±7adjusting the word and character spacing in the printed°dONLNdvÌ<˘…(ZWoutput so that the two widths are identical. If it doesn’t, apparently fully justified °dONLNdÕÌ…˘˛(Á text on the°dONLNdŸ˘<t(!Z screen may °dONLNd‰˘t˛)8Qappear ragged on the paper, and certain lines of text may extend beyond the right°dONLNd6<^(-Zborder °dONLNd=^˛)"Xand be badly clipped. Many existing applications make this task really difficult for the°dONLNdñ<c(9Z;printer drivers (don’t blame them, though!). They position °dONLNd—c˛(9Åthe words (or even characters)°dONLNd<)L(EZ;separately on a line, and the printer driver has to figure °dONLNd+L)˛(Ej$out how to collect the complete line°dONLNdP)<5´(QZSbefore applying its line layout algorithm to distribute the difference of the text °dONLNd£)´5˛(Q…widths into word°dONLNd¥5<A€(]ZYand character spacing. Given the uneven distribution of the character width differences, °dONLNd
  6749. 5€A˛(]˘and the°dONLNdA<M§(iZNrequirement of achieving good typographical quality in the printed output, it °dONLNdcA§M˛(i¬is unavoidable that°dONLNdwM<YÚ(uZ\the position and width of a word within a justified line differs slightly from what appears °dONLNd”MÚY˛(uon°dONLNd÷Y<eN(ÅZ<the screen; only the length of the whole line is maintained.°dONLNdq<}¯*^In computing the required line layout adjustments, the LaserWriter driver proceeds as follows:°dONLNdrä<ñF*1.°dONLNduäNñû)It collects text °dONLNdÜäûñq)P'coming through the printing grafPort’s °dONLNd≠âqï©)”textProc°dONLNdµä©ñ˛)8 bottleneck, and°dONLNdΔñN¢(æl,heuristically puts it together into what it °dONLNdÚñ¢˛)ƒ2“believes” is a logically contiguous line of text.°dONLNd    %¢NÆL( l2This includes text moved vertically away from the °dONLNd    W¢LÆ˛)˛$baseline, to take care of indices or°dONLNd    |ÆN∫](÷l8exponents in the text. The process of accumulating text °dONLNd    ¥Æ]∫˛(÷{is stopped when the LaserWriter°dONLNd    ‘∫NΔL(‚l4driver detects that the horizontal component of the °dONLNd
  6750. ∫LΔ˛)˛"pen position has changed since the°dONLNd
  6751. +«N”ª(ÔlAprevious text drawing instruction, or when picture comments like °dONLNd
  6752. lΔª“˙(ÔŸ    TextBegin°dONLNd
  6753. u«˙”˛)?,°dONLNd
  6754. w”Nfl(¸lTextEnd°dONLNd
  6755. ~‘‡Ü)1, °dONLNd
  6756. Ä”Üfl”) StringBegin°dONLNd
  6757. ã‘”‡⁄)M, °dONLNd
  6758. ç”⁄fl)    StringEnd°dONLNd
  6759. ñ‘‡j)? are encountered.°dONLNd
  6760. ®Ï<¯F(Z2.°dONLNd
  6761. ´ÏN¯‡)XIt determines the width of the accumulated logical line of text, both on the screen and °dONLNd χ¯˛(˛on the°dONLNd
  6762. ¯N>( l5printer, and distributes the line layout error among °dONLNd ?¯>˛)(the interword and intercharacter spacing°dONLNd hN≤(,lof the printed output.°dONLNd <)Q(EZThe °dONLNd ÉQ(¨)
  6763. LineLayoutOff°dONLNd ê¨)A)[ picture comment disables only °dONLNd ØA)˛)ï)the second step (distribution of the line°dONLNd Ÿ)<5i(QZAlayout error); the heuristic algorithm of accumulating text into °dONLNd )i5˛(Qáa logically contiguous piece is°dONLNd :5<A÷(]ZXnot affected. Otherwise, if the character widths of the printer font are different from °dONLNd í5÷A˛(]Ùthose of°dONLNd õA<MØ(iZKthe screen font, and if the text contains exponents or indices, the latter °dONLNd ÊAØM˛(iÕwould often be°dONLNd ıM<Yo(uZ
  6764. misplaced.°dONLNd
  6765. e<qÍ*"The following code fragment shows °dONLNd
  6766. "eÍq˛)Æ6a probably unexpected consequence of this behavior. We°dONLNd
  6767. Yq<}’(ôZ draw a line in two pieces three °dONLNd
  6768. yq’}˛)ô=times. A vertical line shows the starting pen position of the°dONLNd
  6769. ∑~<äf(¶Zsecond °dONLNd
  6770. æ}fâ¨)*
  6771. DrawString°dONLNd
  6772. »~¨äâ)F& call. The second line is enclosed by °dONLNd
  6773. Ó}ââ‰)›
  6774. LineLayoutOff°dONLNd
  6775. ˚~‰äÌ)[ °dONLNd
  6776. ¸~Ìä˛)    and°dONLNdä<ñê(≥Z LineLayoutOn°dONLNd ãêóÍ)T picture comments. ¡X¡
  6777. (÷Z&QD 10 - Picture Comments—The Real Deal(÷ˇ9) of 26(ÏZM.QD.PictCommentsˇ h◊#ˇ ˇˇˇˇ#◊ 
  6778. IR,Times
  6779. .+6-Macintosh Technical Notes /4/˘,
  6780. Courier
  6781.     °dONLNd)4§*#PROCEDURE ObserveLineLayout;°dONLNd=H@*   CONST°dONLNd&GR!*
  6782. 5      testString1 = 'Whatever you like, preferably ';°dONLNd\Q\0*
  6783. 8      testString2 = 'with spaces, long and short words';°dONLNdï[f§*
  6784.       fontName = 'New York';°dONLNd≤ep|*
  6785.       fontSize = 14;°dONLNd«ozΩ*
  6786. !      x0 = 20; { starting point }°dONLNdÈyÑ^*
  6787.       y0 = 40;°dONLNd¯ÉéÆ*
  6788.       h  = 30; { line height }°dONLNdó¢6*   VAR°dONLNd°¨ê*
  6789.       familyID: Integer;°dONLNd7´∂ê*
  6790.       w, y    : Integer;°dONLNdPø @*   BEGIN°dONLNdY…‘¬*
  6791. "      GetFNum(fontName, familyID);°dONLNd|”fiï*
  6792.       TextFont(familyID);°dONLNdñ›Ëï*
  6793.       TextSize(fontSize);°dONLNd≤Ò¸Ã*$      w := StringWidth(testString1);°dONLNd◊˚^*
  6794.       y := y0;°dONLNdʧ*
  6795.       MoveTo(x0 + w, y - h);°dONLNdX*
  6796. @      Line(0, 4 * h);    { This is to estimate the difference. }°dONLNdD#.˘*-      { Draw the first line, in two pieces. }°dONLNdr-8ô*
  6797. M      { This is the default line layout behavior of the LaserWriter driver. }°dONLNd¿7B|*
  6798.       MoveTo(x0, y);°dONLNdflALÆ*
  6799.       DrawString(testString1);°dONLNd˛KVê*
  6800.       MoveTo(x0 + w, y);°dONLNdU`Æ*
  6801.       DrawString(testString2);°dONLNd6it5*9      { Draw the second line, in the same way as above. }°dONLNdps~ô*
  6802. M      { Because of the LineLayoutOff picture comment, the unmodified widths }°dONLNdæ}à€*
  6803. '      { of the printer font are used. }°dONLNdÊáím*
  6804.       y := y + h;°dONLNd¯ëú‡*
  6805. (      PicComment(LineLayoutOff, 0, NIL);°dONLNd!•∞*2                                   { ••• (1)  •••}°dONLNdTØ∫|*
  6806.       MoveTo(x0, y);°dONLNdiπƒÆ*
  6807.       DrawString(testString1);°dONLNdà√Œê*
  6808.       MoveTo(x0 + w, y);°dONLNd°Õÿ*
  6809. 2                                   { ••• (2)  •••}°dONLNd‘◊‚Æ*
  6810.       DrawString(testString2);°dONLNdÛ·Ïm*
  6811.       y := y + h;°dONLNdı€*'      PicComment(LineLayoutOn, 0, NIL);°dONLNd-ˇ
  6812. ‡*
  6813. (      { Back to the original behavior. }°dONLNdV    |*
  6814.       MoveTo(x0, y);°dONLNdkÆ*
  6815.       DrawString(testString1);°dONLNdä(ê*
  6816.       MoveTo(x0 + w, y);°dONLNd£'2Æ*
  6817.       DrawString(testString2);°dONLNd¬;F;*   END;
  6818. °dONLNd R^Ï*.And this is (approximately) the output of the °dONLNd¯QÏ]c)‘ObserveLineLayout°dONLNd    Rc^Ç)w (with °dONLNdRÇ^⁄)LaserWriter driver°dONLNd#^jS(Ü6Dversion 7.1.1, and the default setting “Font Substitution enabled”): ¡4¡˘
  6819. *P10)
  6820.  of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇ∂◊#ˇ ˇˇˇˇ#◊ 
  6821. IR,Times
  6822. .+Z-Developer Support Center(-Ê October 1992 /X/†Ç†å†å°ñ °ö√
  6823. Jvhˇ
  6824. n.UüUü°dONLNdˇˇ(Vw@Whatever you like, preferably with spaces, long and short words n°dONLNdˇˇ*(aaa)†ó
  6825. <kë
  6826.     1Ymi¢    ˇˇˇˇˇˇˇˇ8†ç†å°ñ °ö√
  6827. qvèˇncò°dONLNdˇˇ*@Whatever you like, preferably with spaces, long and short words Q∞°dONLNdˇˇ*(aaa)†ó
  6828. <kë
  6829.     1Ämꢠ   ˇˇˇˇˇˇˇˇ8†ç°ñ °öˇ˚¥
  6830. ]wl‚G0°dONLNdˇˇ(ix?Whatever you like, preferably with spaces, long and short words†ó
  6831. <kë
  6832. "D1@†å0>mç    "?M åoå†ç†ç†É
  6833. IR
  6834. .°dONLNdäã+0>Figure 1—Effect of the ,
  6835. Courier°dONLNd~äz)à
  6836. LineLayoutOff°dONLNd$zã∞)h comment°dONLNd-ó<£z(øZ9For most noticeable effects, we choose the bitmapped New °dONLNdfóz£˛(øòYork font, such that the°dONLNd£<Øò(ÀZLaserWriter driver °dONLNdí£òØ˛)\Isubstitutes PostScript Times (note that there are no line layout problems°dONLNd‹Ø<ªp(◊Z;with TrueType fonts, unless the TrueType font has the same °dONLNdØpª‰(◊éname and different cha°dONLNd.؉ªÚ)trac°dONLNd2ØÚª˛)ter°dONLNd6ª<«µ(„ZKwidths as a printer-resident PostScript font). The screen font New York is °dONLNdŪµ«˛(„”larger than the°dONLNdë«<”œ(ÔZPostScript font Times, and in °dONLNdØ«œ”˛)ìAthe first and third lines, the printer driver (after accumulating°dONLNdÒ”<flâ(¸Z testString1°dONLNd¸‘⇧)M and °dONLNd”§flÒ) testString2°dONLNd ‘Ò‡G)M into one logical °dONLNd‘G‡˛)V'line) distributes the line layout error°dONLNdF‡<ÏÙ(ZU(mainly) among the spaces between words. You may even notice that the starting point °dONLNdõ‡ÙÏ˛(of°dONLNdûÏ<¯â(Z testString2°dONLNd©Ì⢑)MF (“with ...”) has been slightly moved to the left in the process. The °dONLNdÔÌ‘˘˛(Úwidth of°dONLNd¯˘<;(!Z6the whole line, however, is the same as on the screen.°dONLNd/<»*The second line, where the °dONLNdJ»#)å
  6837. LineLayoutOff°dONLNdW#÷)[# comment is active, demonstrates a °dONLNdz÷˛)≥dramatic°dONLNdÉ<*~(FZ?counterexample to the popular belief that this picture comment °dONLNd¬~*˛(Fúis here to assure precise°dONLNd‹*<6,(RZ4positioning of text. It seems the opposite is true, °dONLNd*,6˛)+and the LaserWriter driver has deliberately°dONLNd<7<Ct(_Z ignored the °dONLNdH6tB÷)8MoveTo(x0+w,y)°dONLNdV7÷Cƒ)b2 instruction! What we would have expected is this:†Ç†å†å°ñ °ö√
  6838. |vöˇ
  6839. n.UüUü°dONLNdˇˇ(àw@Whatever you like, preferably with spaces, long and short words n°dONLNdˇˇ*(aaa)†ó
  6840. nk√
  6841.     1ãmõ¢    ˇˇˇˇˇˇˇˇ8†ç†å°ñ °ö√
  6842. £v¡ˇncò°dONLNdˇˇ*@Whatever you like, preferably with spaces, long and short words Q∞°dONLNdˇˇ*(aaa)†ó
  6843. nk√
  6844.     1≤m¬¢    ˇˇˇˇˇˇˇˇ8†ç°ñ °öˇ˚S
  6845. êvüG0°dONLNdˇˇ(úwWhatever you like, preferably†ó°ñ °öˇ˚^
  6846. ê2üÒ.∞°dONLNdˇˇ)º!with spaces, long and short words†ó
  6847. nk√
  6848. "x1>†å0pmø    "qM æoæ†ç†ç†É
  6849. IR
  6850. .°dONLNdâ±sΩ((ŸëFigure 2—Desired result of the °dONLNd®∞(ºê)µ
  6851. LineLayoutOff°dONLNdµ±êΩΔ)h comment°dONLNdæ…<’µ(ÒZMThe attentive reader already knows the explanation. As mentioned earlier, we °dONLNd …µ’˛(Ò”must break the°dONLNd÷<‚)(˛Z1LaserWriter driver’s heuristic line accumulation °dONLNdK÷)‚≠)Ìalgorithm before drawing °dONLNdd’≠·˙)Ñ testString2°dONLNdo÷˙‚˛)M.°dONLNdq„<Ôfi( Z!Short of adequate documentation, °dONLNdí„fiÔÄ)¢!developers have found out that a °dONLNd≥‚ÄÓ˛)¢FlushGrafPortState°dONLNdΔ<¸ë(Zcall right after the °dONLNd€Ôë˚Û)UMoveTo(x0+w,y)°dONLNdÈÛ¸Õ)b2 instruction has the desired effect (see {••• (2) °dONLNdÕ¸˛)⁄ •••} in the°dONLNd'¸<r($ZFcode snippet given earlier). Unfortunately, it creates quite a lot of °dONLNdm¸r˛($êoverhead in the pictures, and°dONLNdã    <â(1ZJpenalizes all printer drivers that don’t need it. A better solution is to °dONLNd’    â±(1ßuse the °dONLNd›±˛)( StringBegin°dONLNdÈ<"Q(>Zand °dONLNdÌQ!ê)    StringEnd°dONLNdˆê"ù)?8 picture comments at the markers {••• (1) •••} and {••• °dONLNd.ù"˛(>ª(2) •••} in the code°dONLNdC#</‡(KZ#shown earlier. This indicates that °dONLNdf"‡.-)§ testString1°dONLNdq#-/≈)M! is to be considered a logically °dONLNdí#≈/˛)ò independent°dONLNdû/<;(WZWtext entity, and must not be put together with any other pieces of text coming through °dONLNdı/;˛(Wthe°dONLNd˘;<Gt(dZtextProc°dONLNd<tH‰)8L bottleneck. The overhead of these comments is much smaller, and they don’t °dONLNdM<‰H˛(daffect°dONLNdTH<T∑(pZother printer drivers at all.°dONLNdra<mT*The °dONLNdv`Tlƒ)ClientLineLayout°dONLNdÜaƒm˛)p; picture comment, supported by the (PostScript) LaserWriter°dONLNd¬m<yª(ïZTdriver, has never been documented. Its effect is rather subtle and very specific to °dONLNd    mªy˛(ïŸthe PostScript°dONLNd    %y<ÖÑ(°ZILaserWriter driver. Basically, it allows the application to redefine the °dONLNd    nyÑÖ˛(°¢character that absorbs the°dONLNd    âÖ<ë[(≠Zmajor °dONLNd    èÖ[ë˛)Wpart of the line layout error (usually the space character), and the percentages of the ¡X¡
  6852. (÷Z&QD 10 - Picture Comments—The Real Deal(÷˙11)
  6853.  of 26(ÏZM.QD.PictCommentsˇ<◊#ˇ ˇˇˇˇ#◊ 
  6854. IR,Times
  6855. .+6-Macintosh Technical Notes /4/˘
  6856. °dONLNd)§*“major” and “minor” parts of °dONLNd§)⁄)åAthe line layout error (usually 80 percent versus 20 percent). The°dONLNd_)5!(Q6:“minor” part is distributed across intercharacter spacing.°dONLNdõAMK*AOnly very ambitious page layout applications might be interested °dONLNd‹AKMé(iiin this functio°dONLNdÏAéMô)Cna°dONLNdÔAôM⁄) lity; but then,°dONLNdˇMYè(u6they should rather aim at °dONLNdMèY⁄)wDa more general scheme of line layout control that does not rely upon°dONLNd^Ye›(Å6*this very driver-specific picture comment.°dONLNdâr~1*The ,
  6857. Courier°dONLNdçq1}Ö) PicComment.p°dONLNdôrÖ~å)T °dONLNdörå~q)+interface (see the Appendix) describes the °dONLNd≈qq}⁄)ÂTClientLLRecord°dONLNd’~äe(¶6Fstructure passed through the handle parameter to the picture comment. °dONLNd~eä⁄(¶ÉIf you want, feel free to°dONLNd5äñ*(≤67experiment with it; we recommend, however, that you do °dONLNdlä*ñ<(≤Hnot°dONLNdoä<ñ∑) use this picture comment °dONLNdâä∑ñ⁄){in your°dONLNdëñ¢O(æ6 application.°dONLNdüÆ∫D*Caveats°dONLNdß«”*•°dONLNd©«%”Î)
  6858. *Some older printer drivers supporting the °dONLNd”ΔΓF)Δ
  6859. LineLayoutOff°dONLNd‡«F”I)[ °dONLNd·«I”⁄)picture comment are unable to°dONLNdˇ‘%‡´(¸Ccorrectly obey a subsequent °dONLNd”´flˇ)Ü LineLayoutOn°dONLNd'‘ˇ‡T)T picture comment.°dONLNd9Ì˘(6•°dONLNd;Ì%˘d)
  6860.  
  6861. Don’t forget °dONLNdHÌd˘≤)?that if you use °dONLNdXÏ≤¯
  6862. )N
  6863. LineLayoutOff°dONLNdeÌ
  6864. ˘⁄)[#, the burden of “WYSIWYG” is now on°dONLNdâ˘%ı(!C-your shoulders, and not the printer driver’s.°dONLNd∑(:6•°dONLNdπ%Á)
  6865. *A previous version of this Note said that °dONLNd„Ál)¬setting the Font Manager’s °dONLNd˛lπ)Ö FractEnable°dONLNd    π⁄)M global°dONLNd%+1(GCto °dONLNd1*M) TRUE°dONLNdM+¬) implied the effect of the °dONLNd3¬*)u
  6866. LineLayoutOff°dONLNd@+⁄)[' picture comment. As it turned out, the°dONLNdh+%7˙(SC)statement was based on observations with °dONLNdë+˙7⁄)’-a specific (older) version of the LaserWriter°dONLNdø8%D(`C3driver, and is not true in general. The setting of °dONLNdÚ7C^)Ï FractEnable°dONLNd˝8^D≥)M does have some °dONLNd
  6867. 8≥D⁄)Umore or°dONLNdD%P‰(lC'less subtle effects on the line layout °dONLNd<D‰P⁄)ø0algorithm, however; and this is quite plausible.°dONLNdmQ%]*(yC0Similarly, the results of combining the picture °dONLNdùQ*]d(yH    comments °dONLNd¶Pd\ø):
  6868. LineLayoutOff°dONLNd≥Qø]⁄)[ and°dONLNd∏]%iy(ÜC LineLayoutOn°dONLNdƒ^yjº)T with calls to °dONLNd”]ºi)C
  6869. SpaceExtra°dONLNd›^j )F (°dONLNdfl^ j^)    Inside Macintosh°dONLNdÔ^^j⁄)S Volume I, page 172) or°dONLNdj%vd(ìC    CharExtra°dONLNdkdwp)? (°dONLNdkpwΔ) Inside Macintosh°dONLNd"kΔwE)V Volume V, page 77) °dONLNd6kEw⁄)are sometimes unpredictable,°dONLNdSw%ÉÍ(üC+depending on the particular printer driver.°dONLNdèõ∑(∑6And Finally the Good News°dONLNdô®¥c*Given that the °dONLNd®®c¥ß)Keffect of the °dONLNd∂ßß≥)D
  6870. LineLayoutOff°dONLNd√®¥)[ and °dONLNd»ß≥s) LineLayoutOn°dONLNd‘®s¥⁄)T comments does not°dONLNdÁ¥¿9(‹6=require any changes in your printing code, you don’t have to °dONLNd$¥9¿⁄(‹W!worry whether or not a particular°dONLNdF¿Ãä(Ë6driver supports them. °dONLNd\¿äÃ⁄)r<They are useful mainly when you’re sure you want no external°dONLNdôÃÿÓ(Ù6+assistance in computing word and character °dONLNdƒÃÓÿ⁄)÷0spacing for full justification, or when you need°dONLNdıÿ‰b(6precise control °dONLNdÿb‰⁄)JJover the horizontal placement of words and characters (such as in forms or°dONLNdP‰( 63tabulated text) and understand how to achieve this.
  6871. °dONLNdÑô*'String Delimitation
  6872. °dONLNdô$0W*    Comments:°dONLNd£#`/≠)H StringBegin°dONLNdÆ$≠0¥)M, °dONLNd∞#¥/Û)    StringEnd°dONLNd∫<H9(d6These °dONLNd¿<9H⁄)!Qcomments allow applications to specify the logical beginning and end of a string,°dONLNd    IU(q67possibly drawn with multiple calls to a QuickDraw text °dONLNd    IIUö(q<drawing routine (such as °dONLNd    bHöT“)|DrawChar°dONLNd    jI“U⁄)8).°dONLNd    mUaS(}6 If this was °dONLNd    yUSa⁄);Mtheir only raison d’être, they would have no relationship with the PostScript°dONLNd    «amx(â6LaserWriter driver. °dONLNd    €axm⁄)`IBut, as already let out in the preceding section on line layout, they are°dONLNd
  6873. %myJ(ï6
  6874. important °dONLNd
  6875. /mJy⁄)2Pto notify the printer driver that it should consider the text coming through the°dONLNd
  6876. ÄyÖP(¢6textProc°dONLNd
  6877. àzPÜ≥)8 bottleneck between °dONLNd
  6878. úy≥Ö)c StringBegin°dONLNd
  6879. ßzÜ)M and °dONLNd
  6880. ¨yÖZ)    StringEnd°dONLNd
  6881. µzZÜ⁄)? as an independent entity.°dONLNd
  6882. –ÜíH(Æ6>Otherwise, the driver might continue to perform its heuristic °dONLNd ÜHí⁄(Æfaccumulation of text drawing ¡4¡˘
  6883. (÷612)
  6884.  of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇ∂◊#ˇ ˇˇˇˇ#◊ 
  6885. IR,Times
  6886. .+Z-Developer Support Center(-Ê October 1992 /X/
  6887. °dONLNd<)Ò(EZ$instructions for the same line, and °dONLNd$Ò)˛)µ5defeat your text positioning intentions. Indeed, both,
  6888. Courier°dONLNdZ)<5â(RZ StringBegin°dONLNde*â6†)M and °dONLNdj)†5fl)    StringEnd°dONLNds*fl6ä)?& trigger the generation of PostScript °dONLNdô*ä6˛)´instructions for drawing°dONLNd≤6<Bu(^Zthe text that °dONLNd¿6uB˛)9Uhas been accumulated in a line layout buffer, and reinitialize the internal variables°dONLNdB<NN(jZfor °dONLNdBNN˛)Uline layout computations. In other words, you need these picture comments to turn the°dONLNdpN<ZG(vZ9LaserWriter driver’s line layout behavior completely off.
  6889. °dONLNd™r<ÅË*'Polygon Comment Family
  6890. °dONLNd¡é<ö{*    Comments:°dONLNdÀçÑô√)H    PolyBegin°dONLNd‘é√ö )?, °dONLNd÷ç ô˚)PolyEnd°dONLNd›é˚ö)1, °dONLNdflçôA)    PolyClose°dONLNdËéAöH)?, °dONLNdÍçHôé)
  6891. PolySmooth°dONLNdÙééöï)F, °dONLNdˆçïô€)
  6892. PolyIgnore°dONLNd¶<≤z(ŒZEPostScript has the built-in capability of drawing cubic Bézier curve °dONLNdF¶z≤Õ(Œòsections (see the °dONLNdX¶Õ≤˛)S
  6893. PostScript°dONLNdc≤<æm(⁄Z    Language °dONLNdl≤mæÀ)1Reference Manual, °dONLNd~≤Àæ˛)^=Second Edition, page 393). This is convenient for “smoothing”°dONLNdºæ< :(ÊZ2of polygons. The polygon-related picture comments °dONLNdÓæ: ˛)˛'have been provided to give applications°dONLNd <÷Ä(ÚZGeasy access to this PostScript feature, with provision for including a °dONLNd] Ä÷˛(ÚûQuickDraw approximation°dONLNdu÷<‚x(˛Z
  6894. of the curve.°dONLNdÉÓ<˙P*8Schematically, the polygon comments are used as follows:°dONLNdΩ`õ+$    PolyBegin°dONLNdΔõÃ);Comment;°dONLNd–u)y{ Put the PostScript °dONLNdÂu˛)adriver into “polygon mode.”°dONLNd<B(:Z}°dONLNd`*Ω+$ ClipRect(zeroRect);°dONLNd*≤)ê&{ Hide the following from QuickDraw. }°dONLNdA*`6ö(R~    PolyClose°dONLNdJ*ö6À):Comment;°dONLNdT*6Ó)z.{ Optionally, if “closed” smoothing desired. }°dONLNdÑ6`B•(^~
  6895. PolySmooth°dONLNdé6•B÷)EComment;°dONLNdó6Bµ)K+{ Tell the driver to draw a Bézier curve. }°dONLNdƒB`N•(j~ DrawPolygon;°dONLNd“BN¯)ê7{ Invisible for QuickDraw; PostScript output = curve. }°dONLNd N`Zü(v~
  6896. PolyIgnore°dONLNdNüZ–)?Comment;°dONLNdNZÌ)Q6{ The driver will ignore the following line drawing. }°dONLNdVZ`f…(Ç~SetClip(origClipRgn);°dONLNdlZfï)ê"{ Make it visible for QuickDraw. }°dONLNdêf`rµ(é~DrawQDPolygon;°dONLNd†frÚ)ê4{ Usually, a QuickDraw approximation of the curve. }°dONLNd÷r`~ê(ö~PolyEnd°dONLNd›rê~¡)0Comment;°dONLNdÁr~»)`,{ PostScript driver resumes standard mode. }°dONLNdä<ñ∑(≤ZA piece of sample code is °dONLNd.ä∑ñ˛){Asometimes worth more than one or two pictures; below, you’ll find°dONLNdpñ<¢å(æZEboth. For clarity and completeness of the exposition, we provide the °dONLNdµñ增(æ™coordinate definition of°dONLNdŒ£<؇(ÀZthe polygons through arrays of °dONLNdÌ¢‡Æ)§Point°dONLNdÚ£Ø_)#s, initialized in a °dONLNd£_Øú)\ preliminary °dONLNd¢úÆ˛)=DefineVertices°dONLNd!∞<º‚(ÿZprocedure. You can enclose the °dONLNd@Ø‚ª/)¶ PolygonDemo°dONLNdK∞/º5)M °dONLNdL∞5ºô)procedure between °dONLNd^ØôªÊ)d OpenPicture°dONLNdi∞ʺ˛)M and°dONLNdnº<»ê(ÂZ ClosePicture°dONLNdzΩê…t)T+ calls to create a picture containing both °dONLNd•Ωt…˛)‰QuickDraw and PostScript°dONLNdæ…<’Ê(ÒZ\representations (see Figures 3 and 4), or you can use it as is when a printing page is open.
  6897.     °dONLNd·<Ïë*USES PicComments;°dONLNd-Î<ˆ≥*
  6898. K{ See Appendix of this Note for the definition of the TPolyRec structure. }°dONLNdyˇ<
  6899. d*   CONST°dONLNdÇ    <;*
  6900. 3      kN = 4; { number of vertices for PostScript }°dONLNd∂<|*
  6901. @      kM = 6; { number of vertices for QuickDraw approximation }°dONLNd˜'<2_*   TYPE°dONLNdˇ1<<|*
  6902. @      PointArray = array[0..0] of Point;  { range checking OFF }°dONLNd    @;<FÊ*
  6903. "      PointArrayPtr = ^PointArray;°dONLNd    cO<Z1*1PROCEDURE DefineVertices(VAR p,q: PointArrayPtr);°dONLNd    ïc<nd*   CONST°dONLNd    ûm<xá*
  6904.       cx = 280;°dONLNd    Æw<Çá*
  6905.       cy = 280;°dONLNd    æÅ<åá*
  6906.       r0 = 200; ¡X¡
  6907. *.&QD 10 - Picture Comments—The Real Deal(÷˙13)
  6908.  of 26(ÏZM.QD.PictCommentsˇ“◊#ˇ ˇˇˇˇ#◊ 
  6909. IR,Times
  6910. .+6-Macintosh Technical Notes /4/˘,
  6911. Courier
  6912.     °dONLNd(@*   BEGIN°dONLNd    '2q*
  6913. E   { The array p^ contains the control points for the Bézier curve: }°dONLNdO1<Æ*
  6914.       SetPt(p^[0],cx + r0,cy);°dONLNdn;FÆ*
  6915.       SetPt(p^[1],cx,cy + r0);°dONLNdçEPÆ*
  6916.       SetPt(p^[2],cx - r0,cy);°dONLNd¨OZÆ*
  6917.       SetPt(p^[3],cx,cy - r0);°dONLNdÀYdÅ*
  6918.       p^[4] := p^[0];°dONLNd·cnô*
  6919. M   { q^ contains the points for a crude polygon approximation of the curve: }°dONLNd/mxÅ*
  6920.       q^[0] := p^[0];°dONLNdEwÇ+*
  6921. 7      SetPt(q^[1],cx,cy + round(0.7 * (p^[1].v - cy)));°dONLNd}Åå{*
  6922. G      SetPt(q^[2],(p^[1].h + p^[2].h) DIV 2,(p^[1].v + p^[2].v) DIV 2);°dONLNd≈ãñ+*
  6923. 7      SetPt(q^[3],cx + round(0.8 * (p^[2].h - cx)),cy);°dONLNd˝ï†˘*
  6924. -      SetPt(q^[4],q^[2].h,cy + cy - q^[2].v);°dONLNd+ü™˘*
  6925. -      SetPt(q^[5],q^[1].h,cy + cy - q^[1].v);°dONLNdY©¥Å*
  6926.       q^[6] := q^[0];°dONLNdo≥æ;*
  6927.    END;°dONLNdw«“Ü*PROCEDURE PolygonDemo;°dONLNdé€Ê6*   VAR°dONLNdïÂï*
  6928.       p,q: PointArrayPtr;°dONLNdØÔ˙≥*
  6929.       aPolyVerbH: TPolyVerbHdl;°dONLNdœ˘m*
  6930.       i: Integer;°dONLNd·¬*
  6931. "      clipRgn, polyRgn: RgnHandle;°dONLNd
  6932. Å*
  6933.       zeroRect: Rect;°dONLNd!,@*   BEGIN°dONLNd#+6?*
  6934. ;      p := PointArrayPtr(NewPtr(SizeOf(Point) * (kN + 1)));°dONLNd_5@?*
  6935. ;      q := PointArrayPtr(NewPtr(SizeOf(Point) * (kM + 1)));°dONLNdõ?JS*
  6936. ?      IF (p = NIL) OR (q = NIL) THEN DebugStr('NewPtr failed');°dONLNd€ITö*
  6937.       DefineVertices(p,q);°dONLNdˆ]hî*L      PenNormal;              { First show the standard QuickDraw polygon. }°dONLNdCgrÆ*
  6938.       MoveTo(p^[0].h,p^[0].v);°dONLNdbq|*
  6939. 2      FOR i := 1 TO kN DO LineTo(p^[i].h,p^[i].v);°dONLNdôÖêî*L      PenSize(2,2);                { Now show the same polygon "smoothed." }°dONLNdÊèöw*
  6940.       PenPat(gray);°dONLNd˙ô§è*
  6941. K      { First, the PostScript representation, clipped off from QuickDraw: }°dONLNdF£Æ]*
  6942. A      aPolyVerbH:= TPolyVerbHdl(NewHandle(SizeOf(TPolyVerbRec)));°dONLNdà≠∏Æ*
  6943.       IF aPolyVerbH<> NIL THEN°dONLNdß∑¬è*
  6944. K         WITH aPolyRecH^^ DO BEGIN        { ••• See comment 1, below. ••• }°dONLNdÛ¡Ã≥*
  6945.             fPolyFrame := TRUE;°dONLNdÀ÷∏*
  6946.              fPolyFill  := FALSE;°dONLNd4’‡è*
  6947. K            fPolyClose := FALSE;     { Compare with the result for TRUE ! }°dONLNdÄflÍê*
  6948.             f3 := FALSE;°dONLNdôÈÙê*
  6949.             f4 := FALSE;°dONLNd≤Û˛ê*
  6950.             f5 := FALSE;°dONLNdÀ˝ê*
  6951.             f6 := FALSE;°dONLNd‰ê*
  6952.             f7 := FALSE;°dONLNd˝Y*
  6953.  
  6954.          END;°dONLNd &è*
  6955. K      MoveTo(p^[0].h,p^[0].v);            { ••• See comment 2, below. ••• }°dONLNdW%0¬*
  6956. "      PicComment(PolyBegin,0,NIL);°dONLNdz/:è*
  6957. K   {  PicComment(PolyClose,0,NIL);  <<< Only if fPolyClose = TRUE, above! }°dONLNdΔ9Dq*
  6958. E      PicComment(PolySmooth,SizeOf(TPolyVerbRec),Handle(aPolyVerbH));°dONLNd CNê*
  6959.       clipRgn := NewRgn;°dONLNd%MXã*
  6960.       GetClip(clipRgn);°dONLNd=Wbï*
  6961.       ClipRect(zeroRect);°dONLNdWal*
  6962. 2      FOR i := 1 TO kN DO LineTo(p^[i].h,p^[i].v);°dONLNdäuÄî*L      { Next, the -crude- QuickDraw approximation of the smoothed polygon, }°dONLNd◊ä5*
  6963. 9      { invisible for PostScript because of PolyIgnore: }°dONLNd    âîã*
  6964.       SetClip(clipRgn); ¡4¡˘
  6965. *&14)
  6966.  of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇ§◊#ˇ ˇˇˇˇ#◊ 
  6967. IR,Times
  6968. .+Z-Developer Support Center(-Ê October 1992 /X/,
  6969. Courier
  6970.     °dONLNd<(Î(DZ#      PicComment(PolyIgnore,0,NIL);°dONLNd$'<2∏*
  6971. L      polyRgn := NewRgn;                   { ••• See comment 3, below. ••• }°dONLNdq1<<Ç*
  6972.       OpenRgn;°dONLNdÄ;<F“*
  6973.       MoveTo(q^[0].h,q^[0].v);°dONLNdüE<P6*
  6974. 2      FOR i := 1 TO kM DO LineTo(q^[i].h,q^[i].v);°dONLNd“O<Z¥*
  6975.       CloseRgn(polyRgn);°dONLNdÎY<d∏*
  6976. L      FrameRgn(polyRgn);         { Or FillRgn, if fPolyFill above is TRUE. }°dONLNd8c<n‹*
  6977.        PicComment(PolyEnd,0,NIL);°dONLNdYw<ǡ*'      DisposHandle(Handle(aPolyVerbH));°dONLNdÅÅ<åæ*
  6978.       DisposeRgn(polyRgn);°dONLNdúã<ñ¥*
  6979.       DisposPtr(Ptr(p));°dONLNdµï<†¥*
  6980.       DisposPtr(Ptr(q));°dONLNdŒü<™_*
  6981.    END;†Ç
  6982. ‘Z£+
  6983.     0Ià:µú9"ü    ˇˇˇˇˇˇˇˇ#†ƒ°d
  6984. ONLNf˛†å†å°d`drw2    "/Ì˙-8@“»Âíˇˇˇˇˇˇ†EÄ"-8ï à˙ÂíÌ“»ï à/@"-8ï     SPC SPC "’¡†æ    q’[†&’¡;&†¡;[’¡†ø    SPC SPC #†††•
  6985. Ñ
  6986. ≥,≥,    ˇˇˇˇˇˇˇˇ#ef#õe#öõ#fö†°°dXdrw2    ILᘙ™ˇˇˇˇˇˇŒ,ᘙ™Iô@Q€ne¿áL    ™U™U™U™U##°d
  6987. ONLNf@#    SPC SPC #    ™U™U™U™U##°d
  6988. ONLNf@#††"9#°¬#Õ    #Ê5†°°dXdrw2    àK«˘UU™™ˇˇˇˇˇˇ},àUU˘™™«ôôöæ 1e33àUUK##°d
  6989. ONLNf@#    SPC SPC #    ™U™U™U™U##°d
  6990. ONLNf@#††":%†?#À˜#Ê †°†ç†å°dXdrw2    BPâ¸UUUU™™ˇˇˇˇˇˇ}âUU¸™™BUUö«ËWªTqà\YP##°d
  6991. ONLNf@#    SPC SPC ":{†æ    qn˛{;(;(3+$˚ÒÁ
  6992. fi    ’ÕΔøˇ∏˛≤˛¨˛ߡ¢öì åáÇ$/}:{†ø††°§";(ûπ#π#¸0Ñ
  6993. ≥,≥,†£†°    SPC SPC #    ™U™U™U™U##°d
  6994. ONLNf@#††°§
  6995. ";(ûπ#π#¸0†£
  6996. ‘Z£+";(Ù¯#Ù¯#ı˘#ˆ˘#ˆ˙#ˆ˚#˜˚#˜¸#¯¸#˘˝#˘˛#˘ˇ#˙ˇ#˙#˚#˚#¯#˘#˘#˚#˚#˝    #˛ #˛ †°°d`drw2    âPœ˝UUġˇˇˇˇˇ}âUU˝œÄöÏfi∫ZóTzäKePEÄ##°d
  6997. ONLNf@#    SPC SPC "<{†æ    qn;{x(;(DLSY˚_ÒeÁifim÷qÕtΔvøw∏x≤x¨xßw£töoìjåcá[ÇRH}<{†ø††°§";(ûG#πÍ#¸–Ñ
  6998. ≥,≥,†£†°    SPC SPC #    ™U™U™U™U##°d
  6999. ONLNf@#††°§
  7000. ";(ûG#πÍ#¸–†£
  7001. ‘Z£+";(Ù    #Ù#ı#ˆ#ˆ#ˆ#˜#¯#˜#˘#˘#˘#˙#˙#˚#¸ˇ#˜˝#˘˚#˘˚#˚˘#˚¯#˝˜#˛ˆ#˛Ù†°°d`drw2    #2Ó˝-8@“»ÂíˇˇˇˇˇˇEÄ#-8ò â˝ÂíÓ“»ò â2@#-8ò     SPC SPC #†††•    ˇˇˇˇˇˇˇˇ"÷ƒef#õe#öõ#fö†°†ç†ç°ddrw2D†É
  7002. IR
  7003. °dONLNd÷êEúÎ+    ÚFigure 3—QuickDraw Output°dONLNdê˘úÙ)¥+Figure 4—PostScript printern printer output°dONLNd¥<¿(‹Z$Additional Comments and Explanations°dONLNdBÕ<ŸF*1.°dONLNdEÕNŸc)The °dONLNdIÃcÿ©)
  7004. fPolyFrame°dONLNdSÕ©Ÿ¿)F and °dONLNdXÿÿˇ)    fPolyFill°dONLNdaÕˇŸ,)?  fields of °dONLNdlÕ,Ÿ>)-the °dONLNdpÃ>ÿv)TPolyRec°dONLNdxÕvŸ˛)8 record are self-explanatory.°dONLNdñ⁄NÊf(lThe °dONLNdöŸf¨)
  7005. fPolyClose°dONLNd§⁄¨Ê()F flag is redundant with °dONLNdº⁄(Ê=)|the °dONLNd¿Ÿ=Â|)    PolyClose°dONLNd…⁄|Ê˛)? picture comment, but is°dONLNd‚ÊNÚË(lVincluded for the convenience of the LaserWriter driver. It is often misunderstood. It °dONLNd8ÊËÚ˛(does°dONLNd=ÚN˛`(lnot°dONLNd@Ú`˛˙) mean the polygon is being °dONLNd[Ú˙˛˛)ö1closed automatically, such as with the PostScript°dONLNdç˛N
  7006. ç('l    closepath°dONLNdñˇç ç)?7 operator; instead, it affects the shape of the smooth °dONLNdÕˇç ˛('´curve. Figure 4 shows°dONLNd„ Nñ(4lthe result for °dONLNdÚ ñ!)HfPolyClose = FALSE;°dONLNd !É)ã the start and end °dONLNd ɲ)bpoint of the polygon is°dONLNd0N%‡(Aldistinguished. In the case of °dONLNdN‡$[)ífPolyClose = TRUE°dONLNd_[%d){, °dONLNdad%˛)    all vertices of the polygon are°dONLNdÅ%N1÷(MlVtreated in the same manner, and the resulting curve resembles a circle (in this case).°dONLNdÿ><JF(fZ2.°dONLNd€>NJ∫)The anonymous fields °dONLNd=∫I‰)lf3..f7°dONLNdˆ>‰J¬)*2 are reserved and should be set to zero (that is, °dONLNd(=¬IÂ)fiFALSE°dONLNd->ÂJÌ)#).°dONLNd0W<cF(Z3.°dONLNd3WNc¡)The polygon is drawn °dONLNdHW¡cÄ)s%at the current pen location when the °dONLNdmVÄbø)ø    PolyBegin°dONLNdvWøc˛)?  comment is°dONLNdÇcNoy(ãl    received.°dONLNdç{<áF(£Z4.°dONLNdê{Ná¨)In general (and in °dONLNd£{¨á")^this example), you do °dONLNdπ{"á4)vnot°dONLNdº{4á˛)( need to open a region, collect the line°dONLNdÂàNîQ(∞l5segments in the region, and draw the polygon through °dONLNdáQìâ(∞oFrameRgn°dONLNd"àâîê)8. °dONLNd$àêî˛)It is demonstrated here ¡X¡
  7007. (÷Z&QD 10 - Picture Comments—The Real Deal(÷˙15)
  7008.  of 26(ÏZM.QD.PictCommentsˇ°¿Ù%%DSIDICT:_cv
  7009. currentdict /bu known {bu}if
  7010. userdict /_cv known not{userdict /_cv 30 dict put}if
  7011. _cv begin
  7012. /bdf{bind def}bind def
  7013. currentscreen/cs exch def/ca exch def/cf exch def
  7014. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7015. /ss{//cf //ca //cs setscreen}bdf
  7016. /stg{ss setgray}bdf
  7017. /strgb{ss setrgbcolor}bdf
  7018. /stcmyk{ss cvcmyk}bdf
  7019. /min1{dup 0 eq{pop 1}if}bdf
  7020. end
  7021. currentdict /bn known {bn}if
  7022. †ø°¿:0.500  userdict /_cv known {_cv begin stg end}{pop}ifelse
  7023. °¿:0.500  userdict /_cv known {_cv begin stg end}{pop}ifelse
  7024. °¿:0.500  userdict /_cv known {_cv begin stg end}{pop}ifelse
  7025. °¿:0.500  userdict /_cv known {_cv begin stg end}{pop}ifelse
  7026. °¿:0.500  userdict /_cv known {_cv begin stg end}{pop}ifelse
  7027. °¿:0.500  userdict /_cv known {_cv begin stg end}{pop}ifelse
  7028. °¿:0.500  userdict /_cv known {_cv begin stg end}{pop}ifelse
  7029. °¿:0.500  userdict /_cv known {_cv begin stg end}{pop}ifelse
  7030. ⁄◊#ˇ ˇˇˇˇ#◊ 
  7031. IR,Times
  7032. .+6-Macintosh Technical Notes /4/˘
  7033. °dONLNd*)B+only °dONLNdB)⁄)Tto prepare you for situations where you want to fill the polygon with a pattern. You°dONLNdZ**6O(RHcannot°dONLNd`*O6w)% open a °dONLNdh*w6Œ)(polygon and use ,
  7034. Courier°dONLNdx)Œ5)WFillPoly°dONLNdÄ*6⁄)8*, because the PostScript driver “owns” the°dONLNd´6*Bü(^HHpolygon concept at this point and captures—and ignores—all line drawing °dONLNdÛ6üB⁄(^Ω between the°dONLNdˇB*Np(kH
  7035. PolyIgnore°dONLNd    CpOá)F and °dONLNdBáN∏)PolyEnd°dONLNdC∏O≠)12 comment. Regions do not interfere with polygons, °dONLNdGC≠O⁄)ıhowever,°dONLNdPO*[(wH5and can be used to paint or fill the polygonal shape.°dONLNdágsD(è6Caveats°dONLNdèã-*9PostScript Level 1 has problems with very large polygons °dONLNd»-ã⁄(ßK"(more than about 1000 points). The°dONLNdÎãój(≥6Gworkaround is to subdivide the large polygon into several smaller ones.°dONLNd3£Ø/*You °dONLNd7£/Ø⁄)Tcannot combine the polygon picture comments with other comments such as the rotation°dONLNdå∞ºi(ÿ6comments or the °dONLNdúØiªØ)Q
  7036. DashedLine°dONLNd¶∞غß)F2 comment. It’s just another limitation—no comment.
  7037. °dONLNd⁄‘„p(ˇ6 Dashed Lines
  7038. °dONLNdÁ¸W*    Comments:°dONLNdÒÔ`˚¶)H
  7039. DashedLine°dONLNd˚¶¸≠)F, °dONLNd˝Ô≠˚Û)
  7040. DashedStop°dONLNd≥(06XPostScript allows applications to draw precisely dashed lines with a given dash pattern °dONLNd`≥⁄(0—in every°dONLNdi!k(=6direction (see the °dONLNd|k ú)Ssetdash°dONLNdÉú!Õ)1  operator, °dONLNdéÕ!é)1&PostScript Language Reference Manual, °dONLNd¥é!¥)¡Second °dONLNdª¥!⁄)&Edition,°dONLNdƒ!-(I63page 500). The QuickDraw ersatz of setting the pen °dONLNd˜!-⁄)ˆ*pattern appears to be awkward at best; the°dONLNd"-9å(U6Hresult depends very much on the direction of the line. Coding correctly °dONLNdj-å9⁄(U™dashed lines in°dONLNdz:F (b6 QuickDraw is quite a hassle and °dONLNdö: F{)≤rather clumsy. This is why the °dONLNdπ9{E¡)±
  7041. DashedLine°dONLNd√:¡F⁄)F and°dONLNd»FR^(o6
  7042. DashedStop°dONLNd“G^Sã)F< picture comments have been provided for applications where °dONLNdGãS⁄(o©dashed lines are°dONLNdS_J({6
  7043. important °dONLNd)SJ_⁄)2Kand used frequently. Applications can take advantage of these comments when°dONLNdu_k´(á6!printing to a PostScript printer.°dONLNdóxÑ.*The °dONLNdõw.Ét)
  7044. DashedLine°dONLNd•xtÑæ)F comment tells °dONLNd¥xæÑ⁄)J;the driver that the line drawing instructions following the°dONLNdÖë4(≠68comment should be dashed according to the parameters in °dONLNd(Ö4ëG(≠Rthe °dONLNd,ÑGêî) TDashedLine°dONLNd7Öîë⁄)M structure (see°dONLNdGëùf(π6Ethe Appendix). These parameters closely correspond to the parameters °dONLNdåëfù⁄(πÑpassed to the PostScript°dONLNd•ù©I(Δ6setdash°dONLNd¨ûI™•)1 operator. Only the °dONLNd¿ù•©›)\centered°dONLNd»û›™)8 field of the °dONLNd÷ù©c)9 TDashedLine°dONLNd·ûc™ù)M structure is °dONLNdÔûù™⁄):
  7045. not currently°dONLNd˝´∑(”69supported by the LaserWriter driver. It should be set to °dONLNd6™∂&(”=0°dONLNd7´&∑≤) in case support for centering °dONLNdV´≤∑⁄)åis added°dONLNd_∑√U(fl6in the future.°dONLNdn–‹î*MUnlike the picture comments for text rotation or even polygon smoothing, the °dONLNdªœî€⁄(¯≤
  7046. DashedLine°dONLNdΔ‹Ëå(6picture comment should °dONLNd›‹åËû)tnot°dONLNd‡‹ûËz). be supported by a non-PostScript driver. The °dONLNd‹zË⁄)‹only way to include°dONLNd"Èı¨(6 representations of dashed lines °dONLNdBȨıA)îwith and without usage of the °dONLNd`ËAÙá)ï
  7047. DashedLine°dONLNdjÈáı⁄)F picture comment°dONLNd{ˆ1(6is to °dONLNdň1Û)&make the following assumption: If the °dONLNdßıÛ9)¬
  7048. DashedLine°dONLNd±ˆ9⁄)F comment is supported, then the°dONLNd—E(+6 printer is °dONLNd‹E—)-a PostScript printer, and the °dONLNd˙—ú)åPostScriptBegin/PostScriptEnd°dONLNd    ú⁄)À  bracket may°dONLNd    $p(76Fbe used to hide the QuickDraw imaging from the printer. Remember that °dONLNd    jp⁄(7énon-PostScript printer    °dONLNd    Å(h(D6
  7049. drivers must 
  7050. °dONLNd    éh(z)Pnot°dONLNd    ëz(S)! ignore QuickDraw imaging within °dONLNd    ≤S'º)ŸPostScriptBegin°dONLNd    ¡º(⁄)i and°dONLNd    Δ(4s(Q6
  7051. PostScriptEnd°dONLNd    ”)s5w)[!°dONLNd    ’BNÊ(j6+But we still need a trick to hide the line °dONLNd
  7052. BÊNà)Œ drawing instructions within the °dONLNd
  7053.  AàMŒ)¢
  7054. DashedLine°dONLNd
  7055. *BŒN⁄)F –°dONLNd
  7056. -NZ^(w6
  7057. DashedStop°dONLNd
  7058. 7O^[√)FG bracket from QuickDraw. Here comes the “magic pen mode” to our rescue: ¡4¡˘
  7059. (÷616)
  7060.  of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇ$◊#ˇ ˇˇˇˇ#◊ 
  7061. IR,Times
  7062. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7063. Courier
  7064.     °dONLNd<(õ(DZPROCEDURE DashDemo;°dONLNd1<<d*   CONST°dONLNd;<F'*
  7065. /      magicPen = 23; { the infamous penMode ! }°dONLNdME<Pá*
  7066.       cx = 280;°dONLNd]O<Zá*
  7067.       cy = 280;°dONLNdmY<dá*
  7068.       r0 = 200;°dONLNd}m<xZ*   VAR°dONLNdÑw<Ç“*
  7069.       dashHdl: TDashedLineHdl;°dONLNd£Å<åë*
  7070.       i: Integer;°dONLNdµã<ñ¥*
  7071.       a, rad : Extended;°dONLNdŒü<™d*   BEGIN°dONLNd◊©<¥õ*
  7072.       PenSize(2,2);°dONLNdÎ≥<æT*
  7073. 8      { First the PostScript picture comment version.  }°dONLNd$Ω<»—*
  7074. Q      { The "magic pen mode" 23 makes the line drawing invisible for QuickDraw. }°dONLNdv«<“¥*
  7075.       PenMode(magicPen);°dONLNdè—<‹ã*
  7076. C      dashHdl := TDashedLineHdl(NewHandle(SizeOf(TDashedLineRec)));°dONLNd”€<Ê»*
  7077.       IF dashHdl <> NIL THEN°dONLNdÂ<‹*
  7078.           WITH dashHdl^^ DO BEGIN°dONLNdÔ<˙'*
  7079. /            offset := 4;       { just for fun }°dONLNdA˘<|*
  7080. @            centered := 0;     { Currently ignored - set to 0. }°dONLNdÇ<|*
  7081. @            intervals[0] := 2; { number of interval specs      }°dONLNd√
  7082. <|*
  7083. @            intervals[1] := 4; { This means 4 points on ...    }°dONLNd<"|*
  7084. @            intervals[2] := 6; { ... and 6 points off.         }°dONLNdE!<,∏*
  7085. L            PicComment(DashedLine, SizeOf(TDashedLineRec), Handle(dashHdl));°dONLNdí+<6}*
  7086.  
  7087.          END;°dONLNd†5<@Å*
  7088. A      rad := 3.14159 / 180;    { Conversion degrees -> radians. }°dONLNd‚?<J^*
  7089. :      FOR i := 0 TO 9 DO BEGIN { Draw some dashed lines. }°dONLNdI<T√*
  7090.          a := i * 20 * rad;°dONLNd9S<^¥*
  7091.          MoveTo(cx, cy);°dONLNdR]<hT*
  7092. 8         Line(round(r0 * cos(a)), - round(r0 * sin(a)));°dONLNdãg<rn*
  7093.  
  7094.       END;°dONLNdñq<|T*
  7095. 8      PicComment(DashedStop, 0, NIL); { That's enough! }°dONLNdœ{<Ü*
  7096. $      DisposHandle(Handle(dashHdl));°dONLNdÙÖ<ê*
  7097. -      PenMode(srcOr);  { No magic any more. }°dONLNd"ô<§≥*K      { Now, the QuickDraw version. The PostScript driver must ignore it, }°dONLNdn£<ÆΩ*
  7098. M      { so we enclose it between PostScriptBegin and PostScriptEnd comments.}°dONLNdº≠<∏*
  7099. *      PicComment(PostScriptBegin, 0, NIL);°dONLNdÁ∑<¬õ*
  7100.       PenSize(2,2);°dONLNd˚¡<Ó*
  7101.       FOR i := 0 TO 9 DO BEGIN°dONLNdÀ<÷Ø*
  7102.          MoveTo(cx,cy);°dONLNd2’<‡@*
  7103. 4         DashedQDLine(round(r0 * cos(i * 20 * rad)),°dONLNdgfl<Ír*
  7104. >                    - round(r0 * sin(i * 20 * rad)), dashHdl);°dONLNd¶È<Ùn*
  7105.  
  7106.       END;°dONLNd±Û<˛˙*
  7107. &      PicComment(PostScriptEnd,0,NIL);°dONLNdÿ˝<_*
  7108.    END;
  7109. °dONLNd‡< ë*By the way: The °dONLNdëÂ)U DashedQDLine°dONLNd¸Â ˛)T; procedure is intentionally missing. It’s not precisely the°dONLNd8 <,¿(HZWsubject of this Note, and thus, again, is left as a spare-time exercise for the reader.°dONLNdê8<Db*Caveat°dONLNdóP<\Z*<As mentioned earlier, the current version of the PostScript °dONLNd”PZ\˛(xx LaserWriter driver produces poor°dONLNdÙ]<iå(ÖZresults when the °dONLNd\åh“)P
  7110. DashedLine°dONLNd]“i‡)F: picture comment is applied to polygons. Just don’t do it! ¡X¡
  7111. (÷Z&QD 10 - Picture Comments—The Real Deal(÷˙17)
  7112.  of 26(ÏZM.QD.PictCommentsˇR◊#ˇ ˇˇˇˇ#◊ 
  7113. IR,Times
  7114. .+6-Macintosh Technical Notes /4/˘
  7115. °dONLNd,¨*Fractional Line Width
  7116. °dONLNd8DQ*Comment:°dONLNd8`D°)H SetLineWidth°dONLNd,P\ß(x6MQuickDraw’s design is based on a fixed 72-dpi resolution. Even when printing °dONLNdyPß\÷(x≈    to a high°dONLNdÇP÷\⁄)/-°dONLNdÉ\hÉ(Ñ6resolution device, the °dONLNdö\Éh⁄)kEPrinting Manager presents the printing grafPort, corresponding to the°dONLNd‡htj(ê6printable area of °dONLNdÚhjt⁄)RHthe page, in the integer-valued QuickDraw coordinate system with 72 dpi.°dONLNd;uÅ|(ù6Applications can use ,
  7117. Courier°dONLNdPt|Ī)d    PrGeneral°dONLNdYuªÅÈ)?
  7118.  to image °dONLNdcuÈÅà)."at higher device resolutions (see °dONLNdÖuàÅ⁄)üInside Macintosh°dONLNdñÅçƒ(©6YVolume V, page 410), but this is useful mainly for immediate printing. As a consequence, °dONLNdÔŃç⁄(©‚lines°dONLNdıçô≠(µ6!are usually always at least 1/72 °dONLNdç≠ô⁄)ï>inch wide, corresponding to the smallest pen size (1,1). For a°dONLNdUô•((¡6;300-dpi device like the LaserWriter, this is disappointing.°dONLNdë≤æ-*The °dONLNdï±-ΩÅ) SetLineWidth°dONLNd°≤Åæå)T: comment allows an application to set the width of a line °dONLNd€≤åæ⁄(⁄™to any fractional°dONLNdÌæ 9(Ê6value. °dONLNdÙæ9 ⁄)!RA value of 1/4 approximately corresponds to a “hairline” on a 300 dpi LaserWriter.°dONLNdGÀ◊Ë(Û6*Curiously (but conveniently), a QuickDraw °dONLNdq Ë÷ )–Point°dONLNdvÀ ◊ã)# structure is passed in the °dONLNdí ã÷—)Ä
  7119. PicComment°dONLNdúÀ—◊⁄)F’s°dONLNdü◊„ (ˇ66data handle, the vertical coordinate representing the °dONLNd’◊ „⁄)Ù*denominator, and the horizontal coordinate°dONLNd„Ô¢( 6the numerator of the fraction.°dONLNd˚—*aUnfortunately, it is not implemented in all high-resolution QuickDraw printers; and if it is (as °dONLNdÄ˚—⁄(#Ôin°dONLNdÉÛ(/6/the LaserWriter SC), it works differently than °dONLNd≤Û⁄)€1in PostScript printer drivers. Moreover, there is°dONLNd‰ F(<6>no possibility to include alternative imaging instructions in °dONLNd"F a(<dcase °dONLNd'aµ) SetLineWidth°dONLNd3µ ⁄)T is not°dONLNd; ,á(H6supported. While this °dONLNdQ á,⁄)oBis not much of a loss for hairlines, it prevents us from using the°dONLNdî-9≥(U6 comment for fractional widths > °dONLNd¥-≥9ï)õ/1, where the alternative would be to include a °dONLNd„,ï8Δ)‚PenSize°dONLNdÍ-Δ9⁄)1 call°dONLNd9E¶(a6Swith rounded arguments. Another drawback may be that, allegedly, there are plotter °dONLNdC9¶E⁄(aƒ drivers out°dONLNdOEQú(m6Sthere that abuse this comment to set the pen color—clearly an unpleasant situation.°dONLNd£^jÂ*,The difference in the implementation of the °dONLNdœ]Âi9)Õ SetLineWidth°dONLNd€^9j⁄)T comment between the PostScript°dONLNd˚kw?(ì6=LaserWriter driver and the LaserWriter SC appears as soon as °dONLNd8j?vì(ì] SetLineWidth°dONLNdDkìw∫)T     is used °dONLNdMk∫w⁄)'for the°dONLNdUwÉ(ü65second time. The PostScript driver keeps an internal °dONLNdäwÉ⁄)˘/line scaling factor; this factor is initialized°dONLNd∫Ñê6(¨69to 1.0 when a job is started. Each number passed through °dONLNdÛÉ6èä(¨T SetLineWidth°dONLNdˇÑäêö)T is °dONLNdÑöê⁄)
  7120. multiplied by°dONLNdêúü(∏6the current internal scaling °dONLNd.êüú⁄)á@factor to get the effective scaling factor for the pen size. The°dONLNdoú®F(ƒ6?LaserWriter SC driver, on the other hand, replaces its current °dONLNdÆúF®⁄(ƒdscaling factor for the pen size°dONLNdŒ©µa(—6completely by °dONLNd‹©aµˇ)Ithe new value passed through °dONLNd˘®ˇ¥S)û SetLineWidth°dONLNd    ©Sµ⁄)T. In order to support both°dONLNd     ∂¬(fi63implementations, you must always use an additional °dONLNd    Sµ¡e)˘ SetLineWidth°dONLNd    _∂e¬≤)T step in order to °dONLNd    q∂≤¬⁄)M    reset the°dONLNd    {¬ŒV(Í6EPostScript driver line width to 1.0, before scaling to the new value.°dONLNd    ¬⁄ÊH*Example°dONLNd     Ú˛n*KLet’s say you have set the line width to 0.25, and want to replace it by a °dONLNd
  7121. Ún˛⁄(åline width of 0.5. The°dONLNd
  7122. ,ˇ K('6
  7123. following °dONLNd
  7124. 6ˇK `)3two°dONLNd
  7125. 9ˇ` e) °dONLNd
  7126. :˛e
  7127. π) SetLineWidth°dONLNd
  7128. Fˇπ ©)T/ comments will have the desired effect on both °dONLNd
  7129. uˇ© ⁄)
  7130. PostScript°dONLNd
  7131. Ä (463(PS) and QuickDraw (QD) drivers that implement the °dONLNd
  7132. ≥ r(4< SetLineWidth°dONLNd
  7133. ø r¡)T comment. You °dONLNd
  7134. Õ ¡⁄)Odon’t°dONLNd
  7135. ”$Z(@6Ccare about the temporary line width of 4.0 on the QuickDraw driver.°dONLNd 06<§+Current Line Width°dONLNd +0¬<%)åParameter Passed°dONLNd <0L<©)äNew Line Width°dONLNd L<.Hd(dL    PS driver°dONLNd V<qH©)C    QD driver°dONLNd `<ΔH")Uin SetLineWidth°dONLNd p<@Hx)z    PS Driver°dONLNd z<~H∏)>    QD Driver°dONLNd ÖN5ZU(wS0.25°dONLNd äNtZî)?0.25°dONLNd èNÂZ˙)q4/1°dONLNd ìNLZa)g1.0°dONLNd óNãZ†)?4.0°dONLNd ú`:lO(âX1.0°dONLNd †`ylé)?4.0°dONLNd §`Âl˙)l1/2°dONLNd ®`Klc)f0.5°dONLNd ¨`äl¢)?0.5°dONLNd ∞xÑ(†65The following sample code gives the expected results °dONLNd ÂxÑ⁄)˛'only on a PostScript LaserWriter and on°dONLNd
  7136. Öë’(≠6(QuickDraw printer drivers that have the °dONLNd 5Ñ’ê))Ω SetLineWidth°dONLNd AÖ)ëö)T comment implemented. ¡4¡˘
  7137. (÷618)
  7138.  of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇ\◊#ˇ ˇˇˇˇ#◊ 
  7139. IR,Times
  7140. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7141. Courier
  7142.     °dONLNd)<4Y(PZ9PROCEDURE SetNewLineWidth(oldWidth,newWidth: TLineWidth);°dONLNd:=<HZ*   VAR°dONLNdAG<R‹*
  7143.        tempWidthH: TLineWidthHdl;°dONLNdb[<fd*   BEGIN°dONLNdke<pÅ*
  7144. A      tempWidthH := TLineWidthHdl(NewHandle(SizeOf(TLineWidth)));°dONLNd≠o<z@*
  7145. 4      { If tempWidthH = NIL we are screwed anyway. }°dONLNd‚y<ÑÎ*
  7146. #      tempWidthH^^.v := oldWidth.h;°dONLNdÉ<éÎ*
  7147. #      tempWidthH^^.h := oldWidth.v;°dONLNd*ç<òï*
  7148. E      PicComment(SetLineWidth,SizeOf(TLineWidth),Handle(tempWidthH));°dONLNdpó<¢◊*
  7149.       tempWidthH^^ := newWidth;°dONLNdê°<¨ï*
  7150. E      PicComment(SetLineWidth,SizeOf(TLineWidth),Handle(tempWidthH));°dONLNd÷´<∂ˇ*
  7151. '      DisposHandle(Handle(tempWidthH));°dONLNd˛µ<¿_*
  7152.    END;°dONLNd”<fi¥*PROCEDURE LineWidthDemo;°dONLNdÁ<Úd*   CONST°dONLNd(Ò<¸Î*
  7153. #      y0 = 50;  { topleft of demo }°dONLNdL˚<Ç*
  7154.       x0 = 50;°dONLNd[<"*
  7155. .      d0 = 440; { length of horizontal lines }°dONLNdä<*
  7156. *      e0 = 5;   { distance between lines }°dONLNdµ<$Î*
  7157. #      kN = 5;   { number of lines }°dONLNdŸ#<.Z*
  7158.    VAR°dONLNd‡-<8h*
  7159. <      oldWidth,newWidth: TLineWidth;  { actually a "Point" }°dONLNd7<B•*
  7160.       i,j,y: Integer;°dONLNd3K<Vd*   BEGIN°dONLNd<U<`å*
  7161.       PenNormal;°dONLNdM_<jÇ*
  7162.       y := y0;°dONLNd\i<tÜ*
  7163. B      SetPt(oldWidth,1,1);             { initial linewidth = 1.0 }°dONLNdüs<~“*
  7164.       FOR i := 1 TO 5 DO BEGIN°dONLNdæ}<àÕ*
  7165.          SetPt(newWidth,4,i);°dONLNd‹á<íÜ*
  7166. B                  { want to set it to i/4 = 0.25, 0.50, 0.75 ... }°dONLNdë<ú*
  7167. ,         SetNewLineWidth(oldWidth,newWidth);°dONLNdLõ<¶Ø*
  7168.          MoveTo(x0, y);°dONLNdd•<∞•*
  7169.          Line(d0, 0);°dONLNdzØ<∫•*
  7170.          y := y + e0;°dONLNdêπ<ƒ“*
  7171.          oldWidth := newWidth;°dONLNdØ√<Œn*
  7172.  
  7173.       END;°dONLNd∫Õ<ÿ_*
  7174.    END;
  7175. °dONLNd¬„<Ô@*•°dONLNd√„@Ôª)A Slight Imperfection°dONLNdŸÔ<˚A(Z•°dONLNd€˚<A* •°dONLNd‹˚AΔ)If you experiment with the °dONLNd˜˚Δ˛)Ö=above code and draw a whole series of hairlines, you will see°dONLNd5<É(0Z(depending on °dONLNdCÉ≈)Gthe values of °dONLNdQ≈”)Be0°dONLNdS”Ï) and °dONLNdXÏ˙)kN°dONLNdZ˙˛)8) that certain lines appear thicker than they should be.°dONLNdì< Ì(<ZXThis is due to rasterization effects in PostScript’s scan conversion algorithm when the °dONLNdÎÌ ˛(< line°dONLNd <,L(HZ<width is close to the device pixel size. In many cases, the °dONLNd, L,˛(Hj&PostScript LaserWriter driver tries to°dONLNdS,<8^(TZ3compensate for this by rounding coordinates to the °dONLNdÜ,^8˛(T|300-dpi grid. If you include°dONLNd£8<Dê(aZ SetLineWidth°dONLNdØ9êE∑)T     (or, by °dONLNd∏9∑EÂ)'    the way, °dONLNd¡8ÂD+).
  7176. DashedLine°dONLNdÀ9+E˛)F*) picture comments, however, this does not°dONLNdˆE<Q<(mZ3work. PostScript Level 2 addresses this problem by °dONLNd)E<Q©(mZmeans of an optional °dONLNd>E©Q˛)mstroke adjustment°dONLNdPQ<]Ü(yZfeature (see the °dONLNdaQÜ]G)J&PostScript Language Reference Manual, °dONLNdáQG]ì)¡Second Edition,°dONLNdñQì]ñ)L °dONLNdóQñ]˜)pages 322 and 515). ¡X¡
  7177. (÷Z&QD 10 - Picture Comments—The Real Deal(÷˙19)
  7178.  of 26(ÏZM.QD.PictCommentsˇ
  7179. ◊#ˇ ˇˇˇˇ#◊ 
  7180. IR,Times
  7181. .+6-Macintosh Technical Notes /4/˘
  7182. °dONLNd,ê*Graphics Rotation
  7183. °dONLNd9EW*    Comments:,
  7184. Courier°dONLNd8`D≠)H RotateBegin°dONLNd'9≠E¥)M, °dONLNd)8¥D) RotateCenter°dONLNd59E)T, °dONLNd78DN)    RotateEnd°dONLNdAQ]õ(y6Like the picture comments °dONLNd[Qõ]⁄)ÉBdiscussed earlier in this Note in the section “Text Rotation,” the°dONLNdû]iÃ(Ö6#graphics rotation picture comments °dONLNd¡]Ãi⁄)¥1provide a method of rotating QuickDraw objects on°dONLNdÛiuª(ë6YPostScript devices. Instead of having QuickDraw perform the rotation, the printer driver °dONLNdLiªu⁄(ëŸrotates°dONLNdTvÇÌ(û6/the entire PostScript coordinate space so that °dONLNdÉvÌÇ))’
  7185. everything°dONLNdçv)ÇM)< drawn °dONLNdîvMÇx)$between °dONLNdúuxÅ≈)+ RotateBegin°dONLNdßv≈Ç⁄)M and°dONLNd¨ÇéW(´6    RotateEnd°dONLNdµÉWèo)? will °dONLNdªÉoè⁄)Mbe rotated on the printer itself. This includes text drawing! You specify the°dONLNd    êúá(∏6center of rotation with °dONLNd!èáõ€)o RotateCenter°dONLNd-ê€ú≈)T2 and the angle of the rotation, together possibly °dONLNd_ê≈ú⁄)Íwith°dONLNddù©·(≈6-horizontal or vertical flipping, through the °dONLNdëú·® )…    TRotation°dONLNdöù ©⁄)?) record (see the interface definitions in°dONLNdƒ©µ_(—6the Appendix).°dONLNd”¡ÕO* Unlike text °dONLNdfl¡OÕ⁄)7Rrotation, you must insert the RotateCenter comment and pass the relative offset to°dONLNd2ÕŸÄ(ı6the center of rotation °dONLNdIÕÄŸ§)hbefore°dONLNdOÕ§Ÿè)$. you use the RotateBegin picture comment. The °dONLNd}ÕèŸ⁄)Îpoint passed to°dONLNdçŸÂø(6"RotateCenter specifies the offset °dONLNdØŸøÂ¿)ß0from the anchor point of the first object drawn °dONLNdflŸ¿Â⁄(fiafter°dONLNdÂÂÒc(
  7186. 6RotateBegin to °dONLNdÙÂcÒ⁄)KLthe desired center of rotation. Once you set up the rotation parameters with°dONLNdAÒ˝©(6SRotateCenter and RotateBegin, you can draw the graphics objects you want to rotate.°dONLNdï    ∂* Bad news: In order to include a °dONLNdµ    ∂⁄)û;QuickDraw representation of the rotated objects in case the°dONLNdÒ!_(=6Drotation comments are not supported, we have to assume (again) that °dONLNd5_!x(=}only°dONLNd9x!{) °dONLNd:{!∂)
  7187. PostScript°dONLNdD∂!π); °dONLNdEπ!⁄)drivers°dONLNdM!-À(I6#implement these comments. The only °dONLNdp!À-⁄)≥7way to hide the QuickDraw substitute from the driver is°dONLNd®.:n(V6to surround it by °dONLNd∫-n9◊)VPostScriptBegin°dONLNd….◊:€)i °dONLNd .€:Ò)and °dONLNdŒ-Ò9L)
  7188. PostScriptEnd°dONLNd€.L:⁄)[ comments; and, similarly to°dONLNd¯;G)(c6the °dONLNd¸:)Fo)
  7189. DashedLine°dONLNd;oGµ)F
  7190.  comment, we °dONLNd;µG⁄)F;need to use the “magic pen mode” (23) to hide the unrotated°dONLNdOHTn(p6drawing between °dONLNd_GnSª)V RotateBegin°dONLNdjHªT‘)M and °dONLNdoG‘S)    RotateEnd°dONLNdxHTÜ)? from QuickDraw. The °dONLNdçHÜT⁄)sfollowing sample°dONLNdûT`m(|6demonstrates this:
  7191.     °dONLNd±lwI*=PROCEDURE QDRotatedRect(r: Rect; ctr: Point; angle: Integer);°dONLNdÔvÅ@*
  7192.    BEGIN°dONLNd¯ÄãN*
  7193. >      { An exercise again - this one is easy ...             }°dONLNd7äïN*
  7194. >      { Rotates the four points of the rectangle by "angle"  }°dONLNdvîüN*
  7195. >      { around the center obtained by adding the point "ctr" }°dONLNdµû©N*
  7196. >      { as offset to r.topLeft, and draws the rotated Rect.  }°dONLNdÙ®≥;*
  7197.    END;°dONLNd¸Δ—X*@PROCEDURE PSRotatedRect(r: Rect; offset: Point; angle: Integer);°dONLNd=–€v*
  7198. F{ Does the rectangle rotation for the PostScript LaserWriter driver. }°dONLNdÑ⁄Âv*
  7199. F{ Uses the RotateCenter, RotateBegin and RotateEnd picture comments, }°dONLNdÀ‰Ôv*
  7200. F{ and the "magic" pen mode 23 to hide the drawing from QuickDraw.    }°dONLNd    ¯@*   CONST°dONLNd    
  7201. |*
  7202.       magicPen = 23;°dONLNd    0!6*   VAR°dONLNd    7 +ö*
  7203.       rInfo: TRotationHdl;°dONLNd    R*5ö*
  7204.       rCenter: TCenterHdl;°dONLNd    m4?ö*
  7205.       oldPenMode: Integer;°dONLNd    àHS@*   BEGIN°dONLNd    ëR]I*
  7206. =      rInfo := TRotationHdl(NewHandle(SizeOf(TRotationRec)));°dONLNd    œ\g?*
  7207. ;      rCenter := TCenterHdl(NewHandle(SizeOf(TCenterRec)));°dONLNd
  7208. fqî*
  7209. L      IF (rInfo = NIL) OR (rCenter = NIL) THEN DebugStr('NewHandle failed'); ¡4¡˘
  7210. *I20)
  7211.  of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇ
  7212. J◊#ˇ ˇˇˇˇ#◊ 
  7213. IR,Times
  7214. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7215. Courier
  7216.     °dONLNd<(√(DZ      WITH rInfo^^ DO BEGIN°dONLNd'<2†*
  7217.          rFlip := 0;°dONLNd11<<√*
  7218.          rAngle := - angle;°dONLNdM;<FE*
  7219. 5         rAngleFixed := BitShift(LongInt(rAngle),16);°dONLNdÉE<Pn*
  7220.  
  7221.       END;°dONLNdéY<dÕ*      WITH rCenter^^ DO BEGIN°dONLNd¨c<n·*
  7222. !         x := Long2Fix(offset.h);°dONLNdŒm<x·*
  7223. !         y := Long2Fix(offset.v);°dONLNdw<Çn*
  7224.  
  7225.       END;°dONLNd˚ã<ñ√*      MoveTo(r.left,r.top);°dONLNdï<†π*
  7226.       FlushGrafPortState;°dONLNd1ü<™Ü*
  7227. B      PicComment(RotateCenter,SizeOf(TCenterRec),Handle(rCenter));°dONLNdt©<¥Å*
  7228. A      PicComment(RotateBegin,SizeOf(TRotationRec),Handle(rInfo));°dONLNd∂Ω<»*$      oldPenMode := thePort^.pnMode;°dONLNd€«<“¥*
  7229.       PenMode(magicPen);°dONLNdÙ—<‹õ*
  7230.       FrameRect(r);°dONLNd€<Êæ*
  7231.       PenMode(oldPenMode);°dONLNd#Ô<˙Ê*"      PicComment(RotateEnd,0,NIL);°dONLNdF<Î*#      DisposeHandle(Handle(rInfo));°dONLNdj
  7232. <ı*
  7233. %      DisposeHandle(Handle(rCenter));°dONLNdê<"_*
  7234.    END;°dONLNdò+<6•*PROCEDURE RotateDemo;°dONLNdÆ?<Jd*   CONST°dONLNd∑I<Të*
  7235.       angle = 30;°dONLNd…]<hZ*   VAR°dONLNd–g<r•*
  7236.       spinRect: Rect;°dONLNdÊq<|õ*
  7237.       delta: Point;°dONLNd˙Ö<êd*   BEGIN°dONLNdè<ö*
  7238. (      SetRect(spinRect,100,100,300,200);°dONLNd,ô<§¬*
  7239. N      WITH spinRect DO SetPt(delta,(right - left) DIV 2,(bottom - top) DIV 2);°dONLNd{≠<∏õ*      PenSize(2,2);°dONLNdè∑<¬•*
  7240.       PenPat(ltGray);°dONLNd•¡<ÃT*
  7241. 8      FrameRect(spinRect); { show the unrotated square }°dONLNdfiÀ<÷å*
  7242.       PenNormal;°dONLNdÔfl<Í**      PSRotatedRect(spinRect,delta,angle);°dONLNdÛ<˛«*O { QuickDraw equivalent of the rotated object, hidden from PostScript driver  }°dONLNdj˝<1*
  7243. 1 { because of PostScriptBegin and PostScriptEnd }°dONLNdú<*(      PicComment(PostScriptBegin,0,NIL);°dONLNd≈<&*
  7244. *      QDRotatedRect(spinRect,delta,angle);°dONLNd%<0˙*
  7245. &      PicComment(PostScriptEnd,0,NIL);°dONLNd9<D_*   END; ¡X¡
  7246. *v&QD 10 - Picture Comments—The Real Deal(÷˙21)
  7247.  of 26(ÏZM.QD.PictCommentsˇZ◊#ˇ ˇˇˇˇ#◊ 
  7248. IR,Times
  7249. .+6-Macintosh Technical Notes /4/˘
  7250. °dONLNd,•*PostScript Comments
  7251. °dONLNd9EW*    Comments:,
  7252. Courier°dONLNd8`D…)HPostScriptBegin°dONLNd-9…E–)i, °dONLNd/8–D+)
  7253. PSBeginNoSave°dONLNd<9+E2)[, °dONLNd>82Dç)
  7254. PostScriptEnd°dONLNdK9çEë)[,°dONLNdME`Q–(n~PostScriptHandle°dONLNd^]i©(Ö6The PostScript comments tell °dONLNd{]©i⁄)ëAthe picture interpreter (usually the LaserWriter driver) that the°dONLNdΩiuü(ë6Sapplication is going to communicate with the LaserWriter directly using PostScript °dONLNdiüu⁄(ëΩ code instead°dONLNdvÇ[(û6=of QuickDraw. All QuickDraw drawing instructions between the °dONLNdZu[Ń(ûyPostScriptBegin°dONLNdivƒÇ…)i °dONLNdjv…Ç⁄)and°dONLNdnÇés(´6
  7255. PostScriptEnd°dONLNd{Ésèz)[0 picture comments are ignored. The driver sends °dONLNd´Ézè⁄(´òthe PostScript text°dONLNdøêúe(∏6contained in the °dONLNd–èeõ’)MPostScriptHandle°dONLNd‡ê’ú˙)p     data to °dONLNdÈê˙ú⁄)%.the printer with no preprocessing and no error°dONLNdù©p(≈6checking. When °dONLNd'ùp©)X4the application is finished sending PostScript, the °dONLNd[ú®⁄(≈ù
  7256. PostScriptEnd°dONLNdi©µó(—6comment tells the printer °dONLNdÉ©óµ⁄);driver to resume normal QuickDraw mode. The driver uses the°dONLNdø∂¬M(fi6 PostScript °dONLNd µM¡i)5save°dONLNdŒ∂i¬m) °dONLNdœ∂m¬É)and °dONLNd”µÉ¡¥)restore°dONLNd⁄∂¥¬⁄)1> operators to preserve the state of the PostScript interpreter°dONLNd√œ≤(Î6across the section enclosed °dONLNd5√≤œ»)öby °dONLNd8¬»Œ1)PostScriptBegin°dONLNdG√1œV)i and °dONLNdL¬VŒ±)%
  7257. PostScriptEnd°dONLNdY√±œ⁄)[. Some°dONLNd`œ€œ(˜6$applications do not want to restore °dONLNdÑœœ€⁄)∑6the previous state of the PostScript interpreter after°dONLNdª‹Ëô(6including their PostScript °dONLNd÷‹ôË5)Å code; for these situations, the °dONLNdˆ€5Áê)ú
  7258. PSBeginNoSave°dONLNd‹êË⁄)[
  7259.  comment is a°dONLNdÈıf(6replacement for °dONLNd!ËfÙœ)NPostScriptBegin°dONLNd0ÈœıØ)i1 that does not preserve the state. Clearly, this °dONLNdaÈØı⁄)‡comment°dONLNdiı»(6$should be used with extreme caution.°dONLNdé**:Some state information may be stored in global variables, °dONLNd»*_(6H so nesting °dONLNd”
  7260. _»)5PostScriptBegin°dONLNd‚»⁄)i (or°dONLNdÁ&z(C6PSBeginNoSave)°dONLNdız'ë)b and °dONLNd˙ë&Ï)
  7261. PostScriptEnd°dONLNdÏ'h)[ comments is not allowed.°dONLNd!4@1(\6The °dONLNd%31?°)PostScriptHandle°dONLNd54°@ä)p+ comment gives developers direct access to °dONLNd`4ä@⁄)ÈPostScript from°dONLNdp@Lí(h6applications. Instead of °dONLNdâ@íL⁄)z>having the LaserWriter driver convert QuickDraw calls into the°dONLNd»LX4(t6<corresponding PostScript code, the application can generate °dONLNdL4X⁄(tR#its own PostScript, and transmit it°dONLNd(YeÒ(Å62to the printer or include it in a picture through °dONLNdZYÒe])Ÿthe data handle of the °dONLNdqX]d£)l
  7262. PicComment°dONLNd{Y£e⁄)F  procedure.°dONLNdáeqy(ç6BThe handle contains pure ASCII text; the valid length of the data °dONLNd…eyq⁄(çóis specified in the°dONLNd›q}^(ö6
  7263. PicComment°dONLNdÁr^~÷)F’s size parameter. Don’t °dONLNdr÷~⁄)x7forget to terminate the PostScript text at least with a°dONLNd8~ä∞(¶6Wspace character, or better with a carriage return (ASCII $0D), so that it is separated °dONLNdè~∞ä⁄(¶Œfrom the°dONLNdòäñg(≤6Jfollowing PostScript instructions (either yours, or the printer driver’s).°dONLNd„£Ø|*You must still use °dONLNdˆ¢|ÆÂ)dPostScriptBegin°dONLNd£ÂØ)i (or °dONLNd
  7264. ¢Æ\)
  7265. PSBeginNoSave°dONLNd£\Ø)[) and °dONLNd¢Æ⁄)#
  7266. PostScriptEnd°dONLNd+∞º<(ÿ6around °dONLNd2Ø<ª¨)$PostScriptHandle°dONLNdB∞¨º;)p comments or the LaserWriter °dONLNd_∞;º⁄)è!driver will not properly save and°dONLNdź»È(‰6+restore the PostScript drawing environment.°dONLNdÆ‘‡®*As with all picture comments, °dONLNdÑ®‡⁄)ê=the handle you pass belongs to you and you must dispose of it°dONLNd    
  7267. ‡Ï¢(6when you’re finished with it.
  7268.     °dONLNd    (¯Ã*$PROCEDURE PostScriptLine(s: Str255);°dONLNd    M
  7269. {*
  7270. G{ A utility procedure to transmit a string of PostScript code through }°dONLNd    ï {*
  7271. G{ the PostScriptHandle picture comment to the PostScript printer.     }°dONLNd    ›!{*
  7272. G{ It should be called only between PostScriptBegin and PostScriptEnd  }°dONLNd
  7273. % +Å*
  7274. { picture comments. }°dONLNd
  7275. ;4?6*   VAR°dONLNd
  7276. B>Ih*
  7277.       h: Handle;°dONLNd
  7278. SR]@*   BEGIN°dONLNd
  7279. \\gö*
  7280.       h := NewHandle(256);°dONLNd
  7281. wfq*
  7282. 3      IF h = NIL THEN DebugStr('NewHandle failed');°dONLNd
  7283. ´p{—*
  7284. %      BlockMove(@s[1],h^, Length(s));°dONLNd
  7285. —zÖ
  7286. *
  7287. 1      PicComment(PostScriptHandle, Length(s), h);°dONLNd Ñèh*
  7288.       h^^ := 13; ¡4¡˘
  7289. *+22)
  7290.  of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇ◊#ˇ ˇˇˇˇ#◊ 
  7291. IR,Times
  7292. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7293. Courier
  7294.     °dONLNd<(ã(DZC      PicComment(PostScriptHandle, 1, h); { add a carriage return }°dONLNdD'<2Ø*
  7295.       DisposeHandle(h);°dONLNd\1<<_*
  7296.    END;°dONLNddO<ZÕ*PROCEDURE PostScriptComments;°dONLNdÇc<nd*   BEGIN°dONLNdãm<x*
  7297. $      { First, the simple example: }°dONLNd∞w<Ç*
  7298. (      PicComment(PostScriptBegin,0,NIL);°dONLNdŸÅ<åê*
  7299. D      PostScriptLine('100 100 moveto 0 100 rlineto 100 0 rlineto ');°dONLNdã<ñJ*
  7300. 6      PostScriptLine('0 -100 rlineto -100 0 rlineto');°dONLNdUï<†◊*
  7301.       PostScriptLine('stroke');°dONLNduü<™†*
  7302.       MoveTo(30,30);°dONLNdä©<¥ê*
  7303. D      DrawString('This text does not appear on PostScript devices');°dONLNdœ≥<æ˙*
  7304. &      PicComment(PostScriptEnd,0,NIL);°dONLNdˆ«<“ö*F      { Now, a new PostScript definition you want to keep in the     }°dONLNd=—<‹ö*
  7305. F      { userdict. If you used PostScriptBegin, the definition would  }°dONLNdÑ€<Êö*
  7306. F      { be lost when PostScriptEnd is encountered, because the state }°dONLNdÀÂ<ö*
  7307. F      { previous to the PostScriptBegin comment would be restored.   }°dONLNdÔ<˙˙*
  7308. &      PicComment(PSBeginNoSave,0,NIL);°dONLNd9˘<ˇ*
  7309. '      PostScriptLine('userdict begin');°dONLNda<ˇ*
  7310. '      PostScriptLine('/myFrameRect {');°dONLNdâ
  7311. <E*
  7312. 5      PostScriptLine('250 250 moveto 0 100 rlineto');°dONLNdø<"ï*
  7313. E      PostScriptLine('200 0 rlineto 0 -100 rlineto -200 0 rlineto ');°dONLNd!<,ı*
  7314. %      PostScriptLine('stroke } def');°dONLNd++<6»*
  7315.       PostScriptLine('end');°dONLNdH5<@˙*
  7316. &      PicComment(PostScriptEnd,0,NIL);°dONLNdoI<Tü*G      { Let's test to see if the definition from above is still avail-}°dONLNd∑S<^ü*
  7317. G      { able. This assumes that no font downloading has occurred.     }°dONLNdˇg<r*(      PicComment(PostScriptBegin,0,NIL);°dONLNd(q<|^*
  7318. :      PostScriptLine('//userdict /myFrameRect get exec ');°dONLNdc{<Ü˙*
  7319. &      PicComment(PostScriptEnd,0,NIL);°dONLNdäÖ<ê_*
  7320.    END;
  7321. °dONLNdíû<™b*Caveat°dONLNdô∂<¬*,If you choose to use PostScript directly in °dONLNd≈∂¬˛)·*your pictures, be very careful not to make°dONLNd√<œz(ÎZ assumptions °dONLNd¸√zœ¡)>about Apple’s °dONLNd
  7322. ¬¡Œ›)G"md"°dONLNd√›œ˛)= dictionary (essentially the contents of the former LaserPrep°dONLNdLœ<€(˜Z/file). Otherwise, your pictures will not print °dONLNd{œ€˛)Ÿ0correctly with future versions of the PostScript°dONLNd¨€<Á`(Z=LaserWriter driver. Also, be aware of compatibility problems °dONLNdÈ€`Á˛(~ within the PostScript world, and°dONLNd
  7323. Á<Û/(Z/watch out for printers with PostScript Level 1 °dONLNd9Á/Û˛)Û(and PostScript Level 2 interpreters, and°dONLNdbÛ<ˇ6(Z5“PostScript-compatible” printers (PostScript clones).
  7324. °dONLNdò<&*'FormsPrinting Picture Comments
  7325. °dONLNd∑2<>{*    Comments:°dONLNd¡2Ñ>()HFormsPrinting, EndFormsPrinting°dONLNd·K<WR(sZThe °dONLNdÂJRV≠)
  7326. FormsPrinting°dONLNdÚK≠Wz)[* comment tells the PostScript LaserWriter °dONLNdKzW˛)Õdriver not to clear its page°dONLNd9X<dv(ÄZ
  7327. buffer after °dONLNdFXvd…):printing a page. °dONLNdWW…c9)SEndFormsPrinting°dONLNdgX9d˛)p& turns this mode off. When the page is°dONLNdéd<p∏(åZLcompleted, the application must erase the areas that need to be updated and °dONLNd⁄d∏p˛(å÷ draw the new°dONLNdÁp<|`(òZ:information. The graphics that make up the form are drawn °dONLNd    !p`|˛(ò~only once per page, which may°dONLNd    ?|<à™(§Zimprove performance. °dONLNd    T|™à˛)nECurrently, you need to write special printing code for the PostScript°dONLNd    öà<î1(∞Z3LaserWriter driver if you want to use this comment. ¡X¡
  7328. *&&QD 10 - Picture Comments—The Real Deal(÷˙23)
  7329.  of 26(ÏZM.QD.PictCommentsˇ™◊#ˇ ˇˇˇˇ#◊ 
  7330. IR,Times
  7331. .+6-Macintosh Technical Notes /4/˘
  7332. °dONLNd5DÇ*33(More or Less) Obsolete PostScript Picture Comments
  7333. °dONLNd4Q]W*    Comments:,
  7334. Courier°dONLNd>P`\¥)H SetGrayLevel°dONLNdJQ¥]∏)T,°dONLNdM]`i–(Ü~TextIsPostScript°dONLNd]^–j◊)p, °dONLNd_]◊i)
  7335. ResourcePS°dONLNdi^j$)F, °dONLNdk]$iÜ)PostScriptFile°dONLNdzwÉ/(ü6The °dONLNd~v/ÇÉ) SetGrayLevel°dONLNdäwÉÉ⁄)TA picture comment was designed to provide access to the PostScript°dONLNdÃÉèI(¨6setgray°dONLNd”ÑIêß)1 operator while still °dONLNdÈÑßê⁄)^<drawing with QuickDraw in black-and-white mode. In practice,°dONLNd&êú,(∏6this °dONLNd+ê,ú⁄)Xturned out to be not so useful, however. For most drawing operations, the printer driver°dONLNdÑú®o(ƒ6sets the gray level °dONLNdòúo®⁄)WLto match the foreground color currently stored in the printing grafPort, and°dONLNd©µl(—6the effect of the °dONLNd˜®l¥¿)T SetGrayLevel°dONLNd©¿µ≈)T °dONLNd©≈µ⁄)7comment is often unpredictable. If direct access to the°dONLNd<∂¬L(fi6 PostScript °dONLNdGµL¡})4setgray°dONLNdN∂}¬p)16 operator seems nevertheless desirable, it is easy to °dONLNdÑ∂p¬⁄)Ûinclude the instruction°dONLNdú√œ,(Î6in a °dONLNd°¬,Œú)PostScriptHandle°dONLNd±√úœŒ)p     comment.°dONLNdª‹Ë0(6The °dONLNdø€0Á†)TextIsPostScript°dONLNdœ‹†ËÃ)p     picture °dONLNdÿ‹ÃË⁄),2comment takes all the text coming through standard°dONLNd Èı≥(6QuickDraw text drawing calls (°dONLNd)Ë≥ÙÎ)õDrawChar°dONLNd1ÈÎıÙ)8, °dONLNd3ËÙÙ:)    
  7336. DrawString°dONLNd=È:ıC)F, °dONLNd?ËCÙ{)    DrawText°dONLNdGÈ{ı»)8, and anything °dONLNdVÈ»ı⁄)Melse°dONLNd[ˆà(6that eventually calls the °dONLNduıàπ)pStdText°dONLNd|ˆπC)1  bottleneck), and interprets it °dONLNdúˆC⁄)äas a PostScript program. There°dONLNdªé(*6is no good reason to use °dONLNd‘é⁄)vFthis picture comment, but there is one important reason not to use it:°dONLNdº(76!Printer drivers that do not deal °dONLNd<ºÌ)§    with the °dONLNdEÌ])1TextIsPostScript°dONLNdU]⁄)p comment will print the°dONLNdm'™(C6YPostScript text instead of interpreting it! If you need to transmit pure PostScript code °dONLNdΔ™'⁄(C» directly to°dONLNd“(4b(P6a printer that °dONLNd·(b4„)Junderstands it, use the °dONLNd˘'„3S)ÅPostScriptHandle°dONLNd    (S4⁄)p comment, and include a°dONLNd!4@(\67QuickDraw representation for all other printer drivers.°dONLNdYMY/*The °dONLNd]L/Xu)
  7337. ResourcePS°dONLNdgMuY>)F' picture comment loads PostScript code °dONLNdéM>Y⁄)…from a specified resource. The°dONLNd≠Zf(Ç66resource file is expected to be open at the time that °dONLNd„Zf)Ôthe °dONLNdÁYe_)
  7338. ResourcePS°dONLNdÒZ_f⁄)F comment is used. Under°dONLNd    fr˙(é6-background printing, there are no guarantees °dONLNd6f˙r⁄)‚-the file will still be open when the Printing°dONLNddr~a(ö6FManager needs it. For this reason alone, you should forget about this °dONLNd™ra~⁄(öcomment. If you want to°dONLNd¬~ä2(¶6keep °dONLNd«~2ä⁄)YPostScript instructions in a resource, it is easy to write a small routine that loads the°dONLNd!ãóÍ(≥6-resources and sends their contents using the °dONLNdNäÍñZ)“PostScriptHandle°dONLNd^ãZó])p °dONLNd_ã]ó⁄)comment described earlier°dONLNdyó£S(ø6
  7339. in this Note.°dONLNdáØªz*PostScriptFile°dONLNdï∞zºº)b has the same °dONLNd£∞ºº˙)B problems as °dONLNdØØ˙ª@)>
  7340. ResourcePS°dONLNdπ∞@º⁄)F  described above. Basically, the°dONLNd⁄º»ô(‰6SPrinting Manager cannot guarantee that the file will be available when it’s needed.
  7341. °dONLNd.‡Ôc*'/Appendix: Pascal Interface for Picture Comments
  7342. °dONLNd^¸.*(File°dONLNdc˚.ó) PicComments.p)
  7343.     °dONLNds1(;6CONST°dONLNdy)w*
  7344.    TextBegin = 150;°dONLNdç(3m*
  7345.    TextEnd = 151;°dONLNdü2=Å*
  7346.    StringBegin = 152;°dONLNdµ<Gw*
  7347.    StringEnd = 153;°dONLNd…FQ|*
  7348.    TextCenter = 154;°dONLNdfiP[ã*
  7349.    LineLayoutOff = 155;°dONLNdˆZeÜ*
  7350.    LineLayoutOn = 156;°dONLNd    
  7351. doö*
  7352.    ClientLineLayout = 157;°dONLNd    (nyw*
  7353.    PolyBegin = 160;°dONLNd    <xÉm*
  7354.    PolyEnd = 161;°dONLNd    NÇç|*
  7355.    PolyIgnore = 163;°dONLNd    cåó|*
  7356.    PolySmooth = 164; ¡4¡˘
  7357. *#24)
  7358.  of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇ î◊#ˇ ˇˇˇˇ#◊ 
  7359. IR,Times
  7360. .+Z-Developer Support Center(-Ê October 1992 /X/,
  7361. Courier
  7362.     °dONLNd<(õ(DZ   PolyClose = 165;°dONLNd'<2†*
  7363.    DashedLine = 180;°dONLNd)1<<†*
  7364.    DashedStop = 181;°dONLNd>;<F™*
  7365.    SetLineWidth = 182;°dONLNdUE<Pπ*
  7366.    PostScriptBegin = 190;°dONLNdoO<ZØ*
  7367.    PostScriptEnd = 191;°dONLNdáY<dæ*
  7368.    PostScriptHandle = 192;°dONLNd¢c<n¥*
  7369.    PostScriptFile = 193;°dONLNdªm<xæ*
  7370.    TextIsPostScript = 194;°dONLNd÷w<dž*
  7371.    ResourcePS = 195;°dONLNdÎÅ<åØ*
  7372.    PSBeginNoSave = 196;°dONLNdã<ñ™*
  7373.    SetGrayLevel = 197;°dONLNdï<†•*
  7374.    RotateBegin = 200;°dONLNd0ü<™õ*
  7375.    RotateEnd = 201;°dONLNdD©<¥™*
  7376.    RotateCenter = 202;°dONLNd[≥<æØ*
  7377.    FormsPrinting = 210;°dONLNdsΩ<»æ*
  7378.    EndFormsPrinting = 211;°dONLNdë—<‹—*Q   tJusNone = 0;           { values for the tJus field of the TTxtPicRec record }°dONLNd„€<Êå*
  7379.    tJusLeft = 1;°dONLNdÙÂ<ñ*
  7380.    tJusCenter = 2;°dONLNdÔ<˙ë*
  7381.    tJusRight = 3;°dONLNd˘<å*
  7382.    tJusFull = 4;°dONLNd.
  7383. <—*Q   tFlipNone = 0;         { values for the tFlip field of the TTxtPicRec record }°dONLNdÄ<"Ø*
  7384.    tFlipHorizontal = 1;°dONLNdò!<,•*
  7385.    tFlipVertical = 2;°dONLNdÆ5<@P*TYPE°dONLNd≥?<J»*
  7386.    TTxtPicHdl = ^TTxtPicPtr;°dONLNd–I<T»*
  7387.    TTxtPicPtr = ^TTxtPicRec;°dONLNdÌS<^Õ*
  7388.    TTxtPicRec = PACKED RECORD°dONLNd ]<h‹*
  7389.                     tJus  : Byte;°dONLNd,g<r‹*
  7390.                     tFlip : Byte;°dONLNdNq<|Ã*
  7391. P                   tAngle: Integer;     { clockwise rotation in degrees 0..360 }°dONLNdü{<Ü^*
  7392. :                   tLine : Byte;        { Unused/Ignored }°dONLNd⁄Ö<ê@*
  7393. 4                   tCmnt : Byte;        { reserved }°dONLNdè<öÃ*
  7394. P                   tAngleFixed: Fixed;  { same as "tAngle" in Fixed precision  }°dONLNd`ô<§Ê*
  7395. "               END; { TTxtPicRec }°dONLNdÉ≠<∏‹*    TRotationHdl = ^TRotationPtr;°dONLNd§∑<¬Õ*
  7396.    TRotationPtr = ^TRotation;°dONLNd¬¡<Ã¥*
  7397.    TRotationRec = RECORD°dONLNd€À<÷Î*
  7398. #                    rFlip: Integer;°dONLNdˇ’<‡Ã*
  7399. P                    rAngle: Integer;    { clockwise rotation in degrees 0..360 }°dONLNdPfl<ÍÃ*
  7400. P                    rAngleFixed: Fixed; { same as "rAngle" in Fixed precision  }°dONLNd°È<Ù˙*
  7401. &                 END; { TRotationRec }°dONLNd»˝<»*   TCenterHdl = ^TCenterPtr;°dONLNdÂ<π*
  7402.    TCenterPtr = ^TCenter;°dONLNdˇ<Ã*
  7403. P   TCenterRec = RECORD  {offset from current pen location to center of rotation}°dONLNdP<&»*
  7404.                    y: Fixed;°dONLNdm%<0»*
  7405.                    x: Fixed;°dONLNdä/<:Î*
  7406. #                END; { TCenterRec } ¡X¡
  7407. *Ä&QD 10 - Picture Comments—The Real Deal(÷˙25)
  7408.  of 26(ÏZM.QD.PictCommentsˇê◊#ˇ ˇˇˇˇ#◊ 
  7409. IR,Times
  7410. .+6-Macintosh Technical Notes /4/˘,
  7411. Courier
  7412.     °dONLNd(∏*    TPolyVerbHdl = ^TPolyVerbPtr;°dONLNd!'2∏*
  7413.     TPolyVerbPtr = ^TPolyVerbRec;°dONLNdB1<≥*
  7414.    TPolyVerbRec = PACKED RECORD°dONLNdb;F&*
  7415. 6                     f7,f6,f5,f4, f3,     { reserved }°dONLNdôEPû*
  7416. N                     fPolyClose,          { TRUE = smoothing across endpoint.}°dONLNdËOZû*
  7417. N                     fPolyFill,           { TRUE = Polygon should be filled. }°dONLNd7Ydû*
  7418. N                     fPolyFrame: BOOLEAN; { TRUE = Polygon should be framed. }°dONLNdÜcnÜ*
  7419.                   END;°dONLNdùwÇÃ*$   TDashedLineHdl = ^TDashedLinePtr;°dONLNd¬ÅåÃ*
  7420. $   TDashedLinePtr = ^TDashedLineRec;°dONLNdÁãñΩ*
  7421. !   TDashedLineRec = PACKED RECORD°dONLNd    ï†ä*
  7422. J                       offset   : SignedByte;  { offset into pattern for }°dONLNdYüÙä+¥
  7423. &           { first dash              }°dONLNdÄ©¥ä(–6J                       centered : SignedByte;  { (Ignored)               }°dONLNdÀ≥æä*
  7424. J                       intervals: ARRAY [0..5] { Array of dash intervals }°dONLNdΩ»ä*
  7425. J                                  OF SignedByte; { intervals[0] = number }°dONLNda«“ä*
  7426. J                    END;                         { of interval specs.    }°dONLNd¨€ʬ*"   TLineWidthHdl = ^TLineWidthPtr;°dONLNdœÂ≥*
  7427.    TLineWidthPtr = ^TLineWidth;°dONLNdÔÔ˙N*
  7428. >   TLineWidth    = Point;  { v = numerator, h = denominator. }°dONLNd.≤*R   TClientLLHdl = ^TClientLLPtr;  { used in the ClientLineLayout picture comment }°dONLNdÅ
  7429. ∏*
  7430.     TClientLLPtr = ^TClientLLRec;°dONLNd¢"$*
  7431.   °dONLNd§$"í)  TClientLLRec = RECORD°dONLNdª!,ä(H6J                     chCount : Integer;  { Apply for so many characters. }°dONLNd+6≤*
  7432. R                     major   : Fixed;    { percentage of line layout error to be }°dONLNdY5@≤*
  7433. R                                         { distributed among space characters.   }°dONLNd¨?J≤*
  7434. R                     spcChar : Integer;  { code of character that is to absorb   }°dONLNdˇIT≤*
  7435. R                                         { the "major" line layout error         }°dONLNdRS^≤*
  7436. R                     minor   : Fixed;    { percentage of intercharacter distrib. }°dONLNd•]h≤*
  7437. R                     ulLength: Fixed;    { underline length.                     }°dONLNd¯grÜ*
  7438.                   END;
  7439. °dONLNdï°Ç*/Further Reference: ¿4¿˘°dONLNd"¢*Æ.+
  7440. •°dONLNd$¢<ƈ)$PostScript Language Reference Manual°dONLNdH¢ˆÆ])∫, Adobe Systems Inc.°dONLNd]Æ*∫.(÷H•°dONLNd_Æ<∫ç)Inside Macintosh°dONLNdoÆç∫ˇ)Q, Volumes II, V, and VI°dONLNdá∫*Δ.(‚H•°dONLNdâ∫<ΔÃ)LaserWriter Reference Manual°dONLNd•∫ÃΔ")ê, Addison-Wesley°dONLNd∂Δ*“.(ÓH•°dONLNd∏Δ<“B)/Macintosh Technical Note M.IM.AppPictComments —°dONLNdΓ`fiP+$ 2Every Picture [Comment] Tells Its Story, Don’t It?°dONLNdfi*Í.(H•°dONLNd fi<Í5)/Macintosh Technical Note M.IM.PictAndPrinting —°dONLNdRÍ`ˆ+$ !Pictures and the Printing Manager°dONLNdtˆ*.(H•°dONLNdvˆ<_):develop Issue 3, “Meet PrGeneral” by Pete “Luke” Alexander°dONLNd±&(B63Adobe is a trademark of Adobe Systems Incorporated.°dONLNdÂ&2\* CPostScript is a registered trademark of Adobe Systems Incorporated. ¡4¡˘
  7441. *à26)
  7442.  of 26(÷F&QD 10 - Picture Comments—The Real Deal+YM.QD.PictCommentsˇƒ◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  7443. /ZÅ#
  7444.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7445. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7446. .eRSeRS+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7447. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7448. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7449.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7450. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  7451. IR.°dONLNdo<Ç[(úZ!QD 11 - Pictures and Clip Regions
  7452. °dONLNd"Å<êá*    QuickDraw
  7453. °dONLNd-ú<®t* Revised by:°dONLNd:ú¬®˛(ƒ‡  March 1988°dONLNdF®<¥q(–Z Written by:°dONLNdR®Ñ¥’)HJennifer Jernigan°dONLNdd®æ¥˛(–‹ January 1986°dONLNdq¿<Ãô(ËZJThis note describes a problem that affects creation of QuickDraw pictures. ˜X˜°dONLNdºÊ<Úe*&When a ,
  7454. Courier°dONLNd√ÂeÒù))GrafPort°dONLNdÀÊùÚ%)8 is created, the fields in the °dONLNdÍÂ%Ò])àGrafPort°dONLNdÚÊ]Úa)8 °dONLNdÛÊaÚ˛) are given default values; one of°dONLNdÚ<˛Á(Z'these is the clip region, which is set °dONLNd;ÚÁ˛˛)´7to the rectangle (–32767, –32767, 32767, 32767). If you°dONLNdsˇ< ≥('Zcreate a picture, then call °dONLNdè˛≥
  7455. )w DrawPicture°dONLNdöˇ )M °dONLNdõˇ ˛)6with a destination rectangle that is not the same size°dONLNd“ <Z(4Zas the °dONLNdŸ Zí)picFrame°dONLNd· í⁄)8F without ever changing the default clip region, nothing will be drawn.°dONLNd($<0â(LZFWhen the picture frame is compared with the destination rectangle and °dONLNdn$â0˛(Lßthe picture is scaled, the°dONLNdâ0<<P(XZclip °dONLNdé0P<˛)Yregion is scaled too. In the process of scaling, the clip region you end up overflows and°dONLNdË<<HÓ(dZ:becomes empty, and your picture doesn’t get drawn. If you °dONLNd"<ÓH˛(d call°dONLNd'H<T˘(qZClipRect(thePort^.portRect)°dONLNdBI˘Us)Ω before you record the °dONLNdYIsU˛)zpicture, the picture will be°dONLNdvU<aÈ(}Z!drawn correctly. The clipping on °dONLNdóUÈa˛)≠5the destination port when playing back the picture is°dONLNdÕa<m\(âZCirrelevant: once a picture is incorrectly recorded, it is too late.°dONLNdë<ù¶*0Further Reference: ºXº°dONLNd$ûN™R+
  7456. •°dONLNd&û`™ñ)    QuickDraw ¡X¡
  7457. (÷Z!QD 11 - Pictures and Clip Regions(÷1) of 1(ÏZM.QD.PicturesAndClipRegionsˇ°¿Ù%%DSIDICT:_cv
  7458. currentdict /bu known {bu}if
  7459. userdict /_cv known not{userdict /_cv 30 dict put}if
  7460. _cv begin
  7461. /bdf{bind def}bind def
  7462. currentscreen/cs exch def/ca exch def/cf exch def
  7463. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7464. /ss{//cf //ca //cs setscreen}bdf
  7465. /stg{ss setgray}bdf
  7466. /strgb{ss setrgbcolor}bdf
  7467. /stcmyk{ss cvcmyk}bdf
  7468. /min1{dup 0 eq{pop 1}if}bdf
  7469. end
  7470. currentdict /bn known {bn}if
  7471. †ø◊#ˇ ˇˇˇˇ#◊°d WORDS †å°d WORDR…†Ç 
  7472. /ZÅ#
  7473.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7474. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7475. .WIQkWIQk+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7476. Ä({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7477. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7478.     l+&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7479. BÄ(Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É°dWORD†ç
  7480. IR.°dONLNdo<Ç-(úZQD 12 - Plotting Small Icons
  7481. °dONLNdÅ<êá*    QuickDraw
  7482. °dONLNd(ú<®t* Revised by:°dONLNd4úÑ®‹)HJames Beninghaus°dONLNdEúæ®˛(ƒ‹ October 1989°dONLNdR®<¥q(–Z Written by:°dONLNd^®Ñ¥3)H James Beninghaus & Dennis Hescox°dONLNd®¡¥˛(–fl August 1989°dONLNdã¡<ÕÓ(ÈZ"This Technical Note discusses the ,
  7483. Courier°dONLNd≠¿ÓÃ)≤'SICN'°dONLNd≥¡Õ˛)*) resource format and how to plot one in a°dONLNd›Õ<Ÿt(ˆZGrafPort°dONLNdÂŒt⁄x)8.°dONLNdÁ⁄<Ê›(ZChanges since August 1989:°dONLNd⁄›Ê˚)°>  Corrected errors in the Pascal code and spruced up the rest. X
  7484. °dONLNd@ <è(6Z Introduction
  7485. °dONLNdM'<3∑*Apple first introduced the °dONLNdh&∑2·){'SICN'°dONLNdn'·3˛)*: resource so that the Script Manager could represent which°dONLNd©3<?©([ZMcountry specific resources are installed in the system by displaying a small °dONLNdˆ3©?˛([«icon in the upper°dONLNd@<L(hZ.right corner of the menu bar.  You can pass a °dONLNd6?K>)ÿ'SICN'°dONLNd<@>Ll)*
  7486.  resource °dONLNdF@lL˛).to the Notification Manager or°dONLNdeL<Xä(tZMenu Manager, °dONLNdsLäX˛)NKand they will draw it for you automatically—you should continue to let them°dONLNdøX<d:(ÄZ2do so.  However, if you want to draw a small icon °dONLNdÒX:d˛)˛'in your application’s window, then this°dONLNdd<pÅ(åZNote can help.°dONLNd(}<ây* What does a °dONLNd4|yà£)='SICN'°dONLNd:}£â()* look like?  Following is a °dONLNdV|(àR)Ö'SICN'°dONLNd\}Râ˛)*# representation of a dogcow to help°dONLNdÄâ<ï†(±Zanswer this question:†Ç
  7487. ¿Èçòë®ËPë®ËL¿ÈçÎΠ   ¯˜ˇ¿    ¯˜@¯    ¸¿Ä@¯¸¿Ä@¯!¸¿Ä@¯¸¿Ä@    ¯Å˜@¯¸x<@˘¸x<@¯¸x<@˘¸x<@    ¯˜@˘ ¸x<@¯¸x<@˘Ä¸x<@¯¸x<@ ˙˜@¯¿˛¿‡@˙¿˛¿‡@¯¿˛¿‡@˙ ¿˛¿‡@    ¯˜@˙Ä{¿˛¿@¯{¿˛¿@˚{¿˛¿@¯{¿˛¿@ ˚˜@¯x˛x˛@˚ x˛x˛@¯x˛x˛@˚Äx˛x˛@    ¯˜@¸˛ x˜ΩÔxΩ‡@¯ x˜ΩÔxΩ‡@¸˛ x˜ΩÔxΩ‡@¯ x˜ΩÔxΩ‡@
  7488. ¸ ˛˜@¯ xΩÔ˜Ä@¸Ä˛ xΩÔ˜Ä@¯ xΩÔ˜Ä@˝˝ xΩÔ˜Ä@    ¯˜@˝˝¿¸˜Ä@¯¿¸˜Ä@˝ ˝¿¸˜Ä@¯¿¸˜Ä@
  7489. ˝Ä˝˜@¯¿¸˜Ä@˛¸¿¸˜Ä@¯¿¸˜Ä@˛¸¿¸˜Ä@    ¯˜@˛ ¸ ¿=ÔxÄ@¯ ¿=ÔxÄ@˛Ä¸ ¿=ÔxÄ@¯ ¿=ÔxÄ@
  7490. ˚˜@¯ ¿Ä¿Ä@˚ ¿Ä¿Ä@¯ ¿Ä¿Ä@ ˚ ¿Ä¿Ä@    ¯˜@¯ ¿Ä¿Ä@¯ ¿Ä¿Ä@¯ ¿Ä¿Ä@¯ ¿Ä¿Ä@    ¯˜@    ˙ ¿<¿<@Ä˚ ¿<¿<@Ä˚ ¿<¿<@
  7491. @˚ ¿<¿<@
  7492.  ˚˜@ ˚ ˜º˜º@Ò¿˚ ˜º˜º@„˙ ˜º˜º@˙ ˜º˜º@ ˙˜@ Ò˙˜@         ˙˜@         ˙˜@
  7493. àÄ˚˜@
  7494. áÄ˚˜@ ˛˚™©˜ˇ¿ÎΆÉ
  7495. IR°dONLNdñ¿Ë+Ñ|SICN'°dONLNdûPy)êFatBits°dONLNd¶<)j(EZ@There is reason to believe that this representation is actually °dONLNdÊj)˛(Eàa baby dogcow.  Due to the°dONLNd)<5î(QZEprotective nature of parent dogcows, young dogcows are rarely seen.  °dONLNdF)î5˛(Q≤This one was spotted°dONLNd[5<A„(]Z#during a DTS meeting after it drew °dONLNd~5„A˛)ß<attention to itself by crying “moo! woof!”.  (Note that this°dONLNdªA<Mı(iZXdogcow said “moo! woof!” because it was immature; adult dogcows naturally say, “Moof!”.) ¡X¡
  7496. *mQD 12 - Plotting Small Icons(÷1) of 5(ÏZM.QD.PlottingSmallIconsˇ°¿Ù%%DSIDICT:_cv
  7497. currentdict /bu known {bu}if
  7498. userdict /_cv known not{userdict /_cv 30 dict put}if
  7499. _cv begin
  7500. /bdf{bind def}bind def
  7501. currentscreen/cs exch def/ca exch def/cf exch def
  7502. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7503. /ss{//cf //ca //cs setscreen}bdf
  7504. /stg{ss setgray}bdf
  7505. /strgb{ss setrgbcolor}bdf
  7506. /stcmyk{ss cvcmyk}bdf
  7507. /min1{dup 0 eq{pop 1}if}bdf
  7508. end
  7509. currentdict /bn known {bn}if
  7510. †ø
  7511. L◊#ˇ ˇˇˇˇ#◊ 
  7512. IR,Times
  7513. .+6-Macintosh Technical Notes /4/˘
  7514. °dONLNd)8Ü*''SICN' Resource
  7515. °dONLNdEQ%*A ,
  7516. Courier°dONLNdD%PO)
  7517. 'SICN'°dONLNdEOQ¨)*D resource contains any number of small icon bit images.  Each small °dONLNd\E¨Q⁄(m     icon in a°dONLNdfQ]B(z6'SICN'°dONLNdlRB^¥)*J list describes a 16 by 16 pixel image and requires 32 bytes of storage.  °dONLNd∂R¥^⁄(z“Like an°dONLNdæ^jK(á6'ICN#' °dONLNd≈_Kk‰)3resource, there is no count of °dONLNd‰_‰ké)ô the number of icons stored in a °dONLNd^éj∏)™'SICN'°dONLNd
  7518. _∏k⁄)*.  The°dONLNdlxI(î6
  7519. following °dONLNdkIws)1'SICN'°dONLNd!lsxÇ)*7 resource, in MPW Rez format, contains two small icons:
  7520.     °dONLNdZÑ<èÊ(´Z"resource 'SICN' (1984, "clarus") {°dONLNdé`ôe+$
  7521. {°dONLNdÅéÑô˜)$/* array: 2 elements */°dONLNdú¢Ñ≠~*2$"00 48 00 B4 00 84 40 52 C0 41 A0 81 9F 8E 8F 18"°dONLNd“¨Ñ∑É*
  7522. 3$"40 18 40 18 47 88 48 48 48 48 44 44 3C 3C 00 00",°dONLNd    ¿ÑÀ~*2$"00 48 00 FC 00 FC 40 7E C0 7F E0 FF FF FE FF F8"°dONLNd? Ñ’~*
  7523. 2$"7F F8 7F F8 7F F8 78 78 78 78 7C 7C 3C 3C 00 00"°dONLNdt‘`fle(˚~}°dONLNdwfi<ÈF(Z};
  7524. °dONLNdz“(+6The Right Tools for the Job
  7525. °dONLNdñ'x*HThe Macintosh Toolbox interfaces do not describe all the necessary data °dONLNdfix'⁄(Cñstructures needed to°dONLNdÛ(4N(P6
  7526. work with °dONLNd˝'N3x)6'SICN'°dONLNd(x4±)*  resources. °dONLNd(±4∞)91 As shown in the following example, defining the °dONLNd@'∞3⁄)ˇ'SICN'°dONLNdG4@<(\6type as °dONLNdO4<@⁄)$Wan array of 16 short integers and the handles and pointers to this array type make life°dONLNdß@LT(h6 much easier.°dONLNd¥Xd<*Pascal
  7527.     °dONLNdªp{,*TYPE°dONLNd¿zÖ*
  7528. /       SICN        = ARRAY[0 .. 15] of INTEGER;°dONLNdÑèÔ*
  7529. +       SICNList    = ARRAY[0 .. 0] of SICN;°dONLNdéô≥*
  7530.        SICNPtr     = ^SICNList;°dONLNd<ò£Æ*
  7531.        SICNHand    = ^SICNPtr;
  7532. °dONLNd[Æ∫!*C
  7533.     °dONLNd]Δ—∏* typedef    short       SICN[16];°dONLNd~–€Ω*
  7534. !typedef    SICN        *SICNList;°dONLNd†⁄ÂΩ*
  7535. !typedef    SICNList    *SICNHand;
  7536. °dONLNd¬¸ ï*&The Missing Count
  7537. °dONLNd‘$-*The °dONLNdÿ-#W)'SICN'°dONLNdfiW$ê)*C resource does not provide a count to indicate the number of small °dONLNd!ê$⁄(@Æicons contained°dONLNd1$0≤(L6Xwithin; however, you can easily determine this number by dividing the total size of the °dONLNdâ$≤0⁄(L–resource°dONLNdí0<µ(X6#by the size of a single small icon. ¡4¡˘
  7538. *~2) of 5(÷ÄQD 12 - Plotting Small Icons+
  7539. M.QD.PlottingSmallIconsˇ
  7540. ‘◊#ˇ ˇˇˇˇ#◊ 
  7541. IR,Times
  7542. .+Z-Developer Support Center(-Ê October 1989 /X/
  7543. °dONLNd)<5`(QZPascal,
  7544. Courier
  7545.     °dONLNdA<LU*CONST°dONLNd
  7546. K<Væ*
  7547.        mySICN      = 1984;°dONLNd(U<`K*
  7548. VAR°dONLNd,_<j“*
  7549.        theSICN     : SICNHand;°dONLNdKi<tÕ*
  7550.        theSize     : LONGINT;°dONLNdis<~Õ*
  7551.        theCount    : LONGINT;°dONLNdá}<àÕ*
  7552.        theIndex    : LONGINT;°dONLNd•ë<ú1*1theSICN := SICNHand(GetResource('SICN', mySICN));°dONLNd◊õ<¶“*
  7553. IF (theSICN <> NIL) THEN BEGIN°dONLNdˆ•<∞1*
  7554. 1       theSize := GetHandleSize(Handle(theSICN));°dONLNd(Ø<∫*
  7555. ,       theCount := theSize DIV sizeof(SICN);°dONLNdUπ<ƒP*
  7556. END;
  7557. °dONLNdZœ<€E*C
  7558.     °dONLNd\Á<Ú√*#define mySICN         1984°dONLNdx˚<õ*SICNHand   theSICN;°dONLNdå<õ*
  7559. long       theSize;°dONLNd†<†*
  7560. long       theCount;°dONLNdµ<$†*
  7561. long       theIndex;°dONLNd -<81*1theSICN = (SICNHand) GetResource('SICN', mySICN);°dONLNd¸7<BÇ*
  7562. if (theSICN) {°dONLNd A<L,*
  7563. 0       theSize = GetHandleSize((Handle)theSICN);°dONLNd<K<V    *
  7564. )       theCount = theSize / sizeof(SICN);°dONLNdfU<`A*
  7565. }
  7566. °dONLNdhw<Ü≠*&The Plot 'SICN's
  7567. °dONLNdyì<ü≠*The example procedure °dONLNdèí≠ûÂ)qPlotSICN°dONLNdóìÂü8)8 draws one small °dONLNd®ì8üg)S
  7568. icon of a °dONLNd≤ígûë)/'SICN'°dONLNd∏ìëü˛)* resource.  It takes the°dONLNd—†<¨|(»Z handle from °dONLNd›ü|´≠)@theSICN°dONLNd‰†≠¨^)1# and the position in the list from °dONLNdü^´ñ)±theIndex°dONLNd†ñ¨˛)8 within the rectangle°dONLNd%¨<∏m(’ZtheRect°dONLNd,≠mπ≤)1 of the current °dONLNd<¨≤∏Í)EGrafPort°dONLNdD≠ÍπÓ)8.°dONLNdFΔ<“p(ÓZ
  7569. Following °dONLNdPΔp“◊)4is an example call to °dONLNdf≈◊—)gPlotSICN°dONLNdnΔ“˛)83 which plots all the small icons in a resource into°dONLNd¢“<fiï(˙Zthe same rectangle:°dONLNd∂Í<ˆ`*Pascal
  7570.     °dONLNdΩ<
  7571. ◊*SetRect(theRect, 0, 0, 16, 16);°dONLNd› <Ê*
  7572. "FOR theIndex := 0 TO theCount-1 DO°dONLNd<!*
  7573. ,       PlotSICN(theRect, theSICN, theIndex);
  7574. °dONLNd-,<8E*C
  7575.     °dONLNd/D<O‹* SetRect(&theRect, 0, 0, 16, 16);°dONLNdPN<Y@*
  7576. 4for (theIndex = 0; theIndex < theCount ; ++theIndex)°dONLNdÖX<c*
  7577. -       PlotSICN(&theRect, theSICN, theIndex);
  7578. °dONLNd≥o<{≥*Because PlotSICN uses °dONLNd…n≥zÚ)w    _CopyBits°dONLNd“oÚ{ )? and °dONLNd◊n zJ)    _CopyBits°dONLNd‡oJ{≈)? can move memory, you °dONLNdˆo≈{˛){ should lock°dONLNd|<à(§ZCthe handle to the 'SICN' once the resource is loaded.  Notice that °dONLNdE|àí(§ùthe °dONLNdI{íá )PlotSICN°dONLNdQ| à˛)8
  7579.  procedure ¡X¡
  7580. (÷ZQD 12 - Plotting Small Icons(÷3) of 5(ÏZM.QD.PlottingSmallIconsˇ8◊#ˇ ˇˇˇˇ#◊ 
  7581. IR,Times
  7582. .+6-Macintosh Technical Notes /4/˘
  7583. °dONLNd*X*
  7584. dereferences °dONLNd
  7585. X*l)@the ,
  7586. Courier°dONLNdl)ñ)'SICN'°dONLNdñ*⁄)*@ handle, adds an offset, and copies the resulting value.  If the°dONLNdX*6B(S6'SICN'°dONLNd^+B7%)*1 list moves in memory at this time, the bitmap’s °dONLNdè*%6])„baseAddr°dONLNdó+]7ë)8  is useless.°dONLNd§DPj(l6To play it safe, °dONLNdµCjO¢)RPlotSICN°dONLNdΩD¢PΔ)8 saves °dONLNdƒDΔP⁄)$6a copy of the master pointer flags associated with the°dONLNd˚Q](y62relocatable block, locks the block with a call to °dONLNd-P\*)Ë_HLock°dONLNd3Q*]2)*, °dONLNd5Q2]⁄)$and restores the flags after calling°dONLNdZ]iW(Ü6    _CopyBits°dONLNdc^Wj£)?.  You should °dONLNdq^£j¬)Lnever°dONLNdv^¬j«) °dONLNdw^«j⁄)7examine, set, or clear these flags directly; you should°dONLNdØjv<(í6always °dONLNd∂j<v⁄)$Ouse the routines which are provided by the Memory Manager and Resource Manager.°dONLNdvÇl(û6NNote that it is not necessary to check the value of the flag after getting it.°dONLNdVéö<*Pascal
  7587.     °dONLNd]¶±Ö*IPROCEDURE PlotSICN(theRect: Rect; theSICN: SICNHand; theIndex : INTEGER);°dONLNdß∞ª'*
  7588. VAR°dONLNd´∫≈∏*
  7589.         state       : SignedByte;°dONLNdÃ∫Ã≈≤)¥.{ we want a chance to restore original state }°dONLNd˚ƒœ§(Î6       srcBits     : BitMap;°dONLNdƒÃœè)¥'{ built up around 'SICN' data so we can°dONLNd@ŒŸ
  7590. (ı61                                      _CopyBits }°dONLNdr‚Ì1*BEGIN°dONLNdxϘÙ*
  7591. ,       { check the index for a valid value }°dONLNd•ˆè*
  7592. K       IF (GetHandleSize(Handle(theSICN)) DIV sizeof(SICN)) > theIndex THEN°dONLNdÒ T*
  7593.        BEGIN°dONLNd˛q*E           { store the resource's current locked/unlocked condition }°dONLNdD)*
  7594. /           state := HGetState(Handle(theSICN));°dONLNdt2=è*K           { lock the resource so it won't move during the _CopyBits call }°dONLNd¿<G¬*
  7595. "           HLock(Handle(theSICN));°dONLNd„P[˘*-           { set up the small icon's bitmap }°dONLNdZer*
  7596.            {$PUSH}°dONLNd$doh*
  7597.            {$R-}°dONLNd7dÃoS)¥{ turn off range checking }°dONLNdSny5(ï69           srcBits.baseAddr := Ptr(@theSICN^^[theIndex]);°dONLNdçxÉm*
  7598.            {$POP}°dONLNdüÇçΩ*
  7599. !           srcBits.rowBytes := 2;°dONLNd¡åó
  7600. *
  7601. 1           SetRect(srcBits.bounds, 0, 0, 16, 16);°dONLNdÛ†´:*:           { draw the small icon in the current grafport }°dONLNd.™µ≤*
  7602. R           CopyBits(srcBits,thePort^.portBits,srcBits.bounds,theRect,srcCopy,NIL);°dONLNdÅæ…S*?           { restore the resource's locked/unlocked condition }°dONLNd¡»”˘*
  7603. -           HSetState(Handle(theSICN), state);°dONLNdÔ“›O*
  7604.        END;°dONLNd˚‹Á,*
  7605. END;
  7606. °dONLNd˛
  7607. !*#C
  7608.     °dONLNd!S*?void PlotSICN(Rect *theRect, SICNHand theSICN, long theIndex) {°dONLNdB +©*
  7609.        auto    char    state;°dONLNd` Ã+£)¥+/* saves original flags of 'SICN' handle */°dONLNdå*5Ω(Q6!       auto    BitMap    srcBits;°dONLNdÆ*Ã5î)¥(/* built up around 'SICN' data so we can°dONLNd◊4?([62                                      _CopyBits */°dONLNd
  7610. HS˛*.       /* check the index for a valid value */°dONLNd9R]Ä*
  7611. H       if ((GetHandleSize(Handle(theSICN)) / sizeof(SICN)) > theIndex) {°dONLNdÇfq{*G           /* store the resource's current locked/unlocked condition */°dONLNd p{˛*
  7612. .           state = HGetState((Handle)theSICN); ¡4¡˘
  7613. *?4) of 5(÷ÄQD 12 - Plotting Small Icons+
  7614. M.QD.PlottingSmallIconsˇ¨◊#ˇ ˇˇˇˇ#◊ 
  7615. IR,Times
  7616. .+Z-Developer Support Center(-Ê October 1989 /X/,
  7617. Courier
  7618.     °dONLNd'<2Ω(NZM           /* lock the resource so it won't move during the _CopyBits call */°dONLNdN1<<Ê*
  7619. "           HLock((Handle)theSICN);°dONLNdqE<P'*/           /* set up the small icon's bitmap */°dONLNd°O<ZY*
  7620. 9           srcBits.baseAddr = (Ptr) (*theSICN)[theIndex];°dONLNd€Y<d‹*
  7621.             srcBits.rowBytes = 2;°dONLNd¸c<n6*
  7622. 2           SetRect(&srcBits.bounds, 0, 0, 16, 16);°dONLNd/w<Çh*<           /* draw the small icon in the current grafport */°dONLNdwã<ñ«*OCopyBits(&srcBits,&(*qd.thePort).portBits,&srcBits.bounds,theRect,srcCopy,nil);°dONLNd«ü<™Å*A           /* restore the resource's locked/unlocked condition */°dONLNd    ©<¥"*
  7623. .           HSetState((Handle) theSICN, state);°dONLNd8≥<æd*
  7624.        }°dONLNdAΩ<»A*
  7625. }
  7626. °dONLNdCfl<Óû*&
  7627. That Was Easy
  7628. °dONLNdQ˙<8*4Now that you’ve seen it done, it looks pretty easy. °dONLNdÖ˙8˛)¸& With minor modifications, some of the°dONLNd¨<ß(.ZMtechniques in this Note could also be used to plot a bitmap of any dimension.°dONLNd˙6<B¶*0Further Reference: aXa°dONLNd
  7629. CNOR+
  7630. •°dONLNdC`O±)Inside Macintosh°dONLNdC±O!)Q, Volume I, QuickDraw°dONLNd5ON[R(wl•°dONLNd7O`[±)Inside Macintosh°dONLNdGO±[;)Q, Volume I, Toolbox Utilities°dONLNde[NgR(Él•°dONLNdg[`g±)Inside Macintosh°dONLNdw[±g\)Q, Volume IV, The Memory Manager°dONLNdógNsR(èl•°dONLNdôg`s*)%Technical Note M.IM.OffscreenBitMap —°dONLNd¡sÑ1+$ " Drawing Into an Off-Screen BitMap°dONLNd‰NãR(ßl•°dONLNdÊ`ã)"Technical Note M.IM.DrawingIcons —°dONLNd ãÑóÕ+$  Drawing Icons ¡X¡
  7631. (÷ZQD 12 - Plotting Small Icons(÷5) of 5(ÏZM.QD.PlottingSmallIconsˇF◊#ˇ ˇˇˇˇ#◊†Ç 
  7632. /ZÅ#
  7633.     0Ià:µú9"{    ˇˇˇˇˇˇˇˇ#†ƒ°d
  7634. ONLNf˛†å°d1drw2…-·_ġˇˇˇˇˇè°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˙ó@†ò,Times
  7635. .R…R…+]BNew Technical Notes†ô°ddrw2:°„†ó°d1drw2eÙġˇˇˇˇˇP°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚ÄE¿†ò
  7636. ({ïDeveloper Support†ô°ddrw2:°„†ó°d`drw2-ÔˇˇˇˇˇˇKÔ- Z  ffZ°d1drw2 ¿˙ÈˇˇˇˇˇˇK°ñ x°ddrw2:°ddrw2:$°d4drw2:0°öˇÙĆò
  7637. 0(UÔ†ô°ddrw2:°„†ó°d1drw2ÔÊ˙ˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:    °öˇ˝Ä†ò
  7638.     +&    ®†ô°ddrw2:°„†ó°d1drw2Â-¯yˇˇˇˇˇˇ°ñ x°ddrw2:°ddrw2:$°d4drw2:°öˇ˚Ä%†ò
  7639. (Z\    Macintosh†ô°ddrw2:°„†ó†ç°ddrw2D†É
  7640. IR.°dONLNdn<Åı(õZ2QD 13 - Principia Off-Screen Graphics Environments
  7641. °dONLNd3Ä<èá*    QuickDraw
  7642. °dONLNd>õ<ßv* Updated by:°dONLNdJõÑßÀ)HForrest Tanaka°dONLNdYõ≈߲(√„
  7643. March 1992°dONLNddß<≥q(œZ Written by:°dONLNdpßÑ≥À)HForrest Tanaka°dONLNdßæ≥˛(œ‹ October 1991°dONLNdå≥<øu(€Z Inspired by:°dONLNdô≥Ñø\)H-Jim Friedlander, Rick Blair, and Rich Collyer°dONLNd«À<◊K(ÛZ5Using Color QuickDraw to draw off screen is a common °dONLNd¸ÀK◊˛(Ûi%requirement of applications and other°dONLNd"◊<„Z(ˇZkinds °dONLNd(◊Z„˛)Oof programs that run on the Macintosh. This Note discusses what Color QuickDraw°dONLNdx„<ÔË( ZPneeds in a graphics environment and how to create one for off-screen drawing. A °dONLNd»„ËÔ˛( brief°dONLNdŒÔ<˚(ZUdiscussion of GWorlds, which are off-screen graphics environments that are set up by °dONLNd#Ô˚˛(the°dONLNd'˚<Û(#Z$system, is given to help you decide °dONLNdK˚Û˛)∑4whether to use them or the do-it-yourself techniques°dONLNdÄ<T(/Z=described in this Note for setting up an off-screen graphics °dONLNdΩT˛(/r#environment. The author’s intent is°dONLNd·<H(;Zto °dONLNd‰H˛) Zprovide concepts and routines for creating an off-screen graphics environment, and also to°dONLNd?<+|(GZDexplain why existing routines for off-screen drawing act as they do.°dONLNdÑ7<CQ*Man°dONLNdá7QCW)y°dONLNdà7VC]), °dONLNdä7]C˛)Qmany thanks go to Guillermo Ortiz, Konstantin Othmer, Bruce Leak, and Jon Zap for°dONLNd‹C<O(kZ3all their expertise on this subject, Rich Collyer, °dONLNdCO˛)·.Rick Blair, and Jim Friedlander for paving the°dONLNd>O<[J(wZwa°dONLNd@OJ[P)y°dONLNdAOO[õ), and especially °dONLNdROõ[˛)LIto all people who inspired this update by asking great off-screen drawing°dONLNdú[<gm(ÉZ
  7644. questions.°dONLNdßs<‡*Changes since October 1991°dONLNd¡s‡i)§:  A very embarrassing bug °dONLNd‹si˛)âwas found in CreateOffScreen°dONLNd˘<ã∑(ßZand UpdateOffScreen. If °dONLNd∑ã˛){Byou try to create a 16- or 32-bit off-screen graphics environment,°dONLNdTã<ó (≥Z1you’ll just get a paramErr. It won’t do that now. ¬X¬
  7645. °dONLNdܺ<Àö*4
  7646. Off-Screening
  7647. °dONLNdî◊<„Ï*#The Macintosh, as with every other °dONLNd∑◊Ï„˛)∞0CPU ever made by Apple, has memory-mapped video.°dONLNdË„<ÔÂ( Z$That is, what you see on the screen °dONLNd „ÂÔ˛)©<is just the visual representation of a part of memory that’s°dONLNdIÔ<˚å(Zreserved for the °dONLNdZÔå˚˛)PNvideo hardware (that’s stretching the truth just a bit in the case of the text°dONLNd©˚<«(#ZUscreens of the original Apple computer, the Apple II line, and the Apple III because °dONLNd˛˚«˛(# there’s also°dONLNd <£(/Za character generator °dONLNd!£˛)gGin those, but the overall process still looks roughly the same). If you°dONLNdi<ø(;Zchange the contents of a °dONLNdÇøå)É%memory location in this part of memor°dONLNdßåí)Õy°dONLNd®ë˛), then you’ll see the°dONLNdæ<+ä(GZDcorresponding location on the screen change when the video hardware °dONLNdä+˛(G®draws the next frame or°dONLNd+<7ó(SZfield of video. The °dONLNd.+ó7˛)[Iresident raster graphics package, QuickDraw in the case of the Macintosh,°dONLNdx7<C∑(_Zdraws images by stuffing °dONLNdë7∑C˛){Ethe right values into the right places in the part of memory reserved°dONLNd◊C<Oó(kZfor the video displa°dONLNdÎCóOù)[y°dONLNdÏCúO‰). The resulting °dONLNd¸C‰O˛)H;image on the screen looks like a line or perhaps an oval if°dONLNd    8O<[¯(wZ&you asked QuickDraw to draw a line or °dONLNd    ^O¯[˛)º6an oval, or it could be an entire complex image if you°dONLNd    ï[<gy(ÉZ?asked QuickDraw to draw one. This is normal, on-screen drawing.°dONLNd    ’s<‹*TBecause video memory is a part of RAM just like any other part of RAM in the memory °dONLNd
  7648. )s‹˛(õ˙map of°dONLNd
  7649. 0<ãÇ(ßZBthe Macintosh (or almost like; video memory might exist on a NuBus
  7650.     °dONLNd
  7651. r~Çâä(•†™
  7652. °dONLNd
  7653. säãç+ °dONLNd
  7654. tçã˛)video card, but it’s still°dONLNd
  7655. èã<ó‹(≥ZRAM), QuickDraw can be told to °dONLNd
  7656. Æã‹ó˛)†<draw into a part of memory that isn’t reserved for the video ¡X¡
  7657. (÷Z2QD 13 - Principia Off-Screen Graphics Environments(÷ˇ1) of 51(ÏZM.QD.PrincipiaOffScreenˇ°¿Ù%%DSIDICT:_cv
  7658. currentdict /bu known {bu}if
  7659. userdict /_cv known not{userdict /_cv 30 dict put}if
  7660. _cv begin
  7661. /bdf{bind def}bind def
  7662. currentscreen/cs exch def/ca exch def/cf exch def
  7663. /setcmykcolor where{/setcmykcolor get /cvcmyk exch def}{/cvcmyk{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf }ifelse
  7664. /ss{//cf //ca //cs setscreen}bdf
  7665. /stg{ss setgray}bdf
  7666. /strgb{ss setrgbcolor}bdf
  7667. /stcmyk{ss cvcmyk}bdf
  7668. /min1{dup 0 eq{pop 1}if}bdf
  7669. end
  7670. currentdict /bn known {bn}if
  7671. †ø÷◊#ˇ ˇˇˇˇ#◊ 
  7672. IR,Times
  7673. .+6-Macintosh Technical Notes /4/˘
  7674. °dONLNd)o*hardware, maybe °dONLNdo)⁄)WFinto a part of your own application’s heap. When you tell QuickDraw to°dONLNdW)5©(Q6Udraw into a part of memory that’s not reserved for the video hardware, you can’t see °dONLNd¨)©5⁄(Q«
  7675. any of the°dONLNd∑5AJ(]6Cresults. This is off-screen drawing. There are plenty of perfectly °dONLNd˙5JA⁄(]hgood reasons to do this, such°dONLNdAM$(i66as providing storage for a paint-style document or to °dONLNdNA$M⁄(iB"smoothly animate an image, but the°dONLNdqMY†(u6Sassumption here is that you have a perfectly good reason to do this so you’re more °dONLNdƒM†Y⁄(uæ
  7676. interested in°dONLNd“YeK(Å6
  7677. the “how” °dONLNd‹YKe^)38of it instead of the “why” of it. If you need to know wh°dONLNdY^ed(Å|y°dONLNdYce⁄), there are several books°dONLNd/eq(ç65that cover off-screen drawing and the perfectly good °dONLNddeq⁄)˙(reasons to do such a thing. A good place°dONLNdçq}±(ô6"to start is Scott Knaster’s book, °dONLNdØq±}))ôMacintosh Programming °dONLNd≈q)}K)xSecrets°dONLNdÃqK}⁄)", referenced at the end of this°dONLNdÏ}â3(•6Note.°dONLNdÚï°Ú*/This Note is divided into these major sections:°dONLNd"≠*π(+7• The introduction is the part that you’re reading now.°dONLNdZπ*≈†* • “The Building Blocks” °dONLNdrπ†≈∂)v9provides an overview of the data structures that you need°dONLNd¨≈7—(ÌU+to tell Color QuickDraw to draw off screen.°dONLNdÿ—*›—(˘H"• “Building the Blocks” discusses °dONLNd˙——›∂)ß1the construction and initialization of these data°dONLNd,›7Èi(U structures.°dONLNd8È*ı.(H•°dONLNd:È7ı÷)
  7678. “Playing With Blocks” shows an °dONLNdYÈ÷ı∂)ü.example of the use of these structures to draw°dONLNdàı7j(U off screen.°dONLNdî*
  7679. .()H•°dONLNdñ7
  7680. v)
  7681. >“Put That Checkbook Away!” discusses some variations of these °dONLNd‘v
  7682. ∂()î
  7683. techniques to°dONLNd‚
  7684. 7(5U,handle off-screen drawing for special cases.°dONLNd*%.(AH•°dONLNd7%’)
  7685. “The GWorld Factor” provides a °dONLNd0’%∂)û+brief overview of GWorlds, how to use them,°dONLNd\%71≠(MUNand how they compare and contrast to the manual techniques that are described °dONLNd™%≠1∂(MÀin°dONLNd≠17=ç(YUmost of this Note.°dONLNd¿IU®(q6PThose of you who aren’t quite sure whether to use GWorlds or the do-it-yourself °dONLNdI®U⁄(qΔ
  7686. techniques°dONLNdUaß(}6Smight want to skip ahead for a moment to “The GWorld Factor” just in case doing it °dONLNdnUßa⁄(}≈ yourself is°dONLNdzam◊(â6*a waste of time. In any case, it’s a good °dONLNd§a◊m⁄)ø5idea to read this whole Note because the concepts are°dONLNd⁄my;(ï6mostly °dONLNd·m;y⁄)#Qthe same whether you’re using GWorlds or not. GWorlds just make the process a lot°dONLNd3yÖ…(°6Ueasier, and they let you take advantage of the 8•24 GC video card. But, we’re not in °dONLNdày…Ö⁄(°Áthat°dONLNdçÖëÜ(≠6section of the Note yet.
  7687. °dONLNd¶©∏†*'The Building Blocks
  7688. °dONLNd∫ƒ–Ú*-Before you can tell QuickDraw to draw off of °dONLNdÁƒÚ–⁄)⁄1the screen, you’ll need to build three major data°dONLNd–‹V(¯6structures: a ,
  7689. Courier
  7690. °dONLNd'–V‹å)>    CGrafPort
  7691. °dONLNd0–å‹ù)6, a 
  7692. °dONLNd4–ù‹¡)PixMap
  7693. °dONLNd:–¡‹Á)$, and a 
  7694. °dONLNdB–Á‹)&GDevice
  7695. °dONLNdI–‹)*. °dONLNdK–‹!)Y°dONLNdL– ‹Q) ou’ll also °dONLNdW–Q‹⁄)1need a couple of tables that°dONLNdt‹ËV(6@define the colors involved with drawing to and copying from the °dONLNd¥‹VË⁄(toff-screen image: the color°dONLNd–ËÙ{(6table and the inverse °dONLNdÊË{Ù⁄)cKtable. Of course, you’ll need the pixel image itself, which is often called°dONLNd    2Ùp(6the “pixel buffer” °dONLNd    EÙp⁄)XKor the “image buffer” or the “off-screen buffer” or just “the buffer.” It’s°dONLNd    ë »((6\always called the “pixel image” in this Note. It doesn’t necessarily buffer anything anyway.°dONLNd    Ó$l*
  7696. The CGrafPort°dONLNd    ¸0<$*A 
  7697. °dONLNd    ˛0$<Z)     CGrafPort
  7698. °dONLNd
  7699. 0Z<¬)6 describes a drawing °dONLNd
  7700. 0¬<™)h/environment, and it’s the color version of the 
  7701. °dONLNd
  7702. K0™<⁄)ËGrafPort
  7703. °dONLNd
  7704. T<He(d6structure that’s °dONLNd
  7705. e<eHΩ)M?described on pages 147 through 155 in the QuickDraw chapter of °dONLNd
  7706. §<ΩH⁄(d€Inside°dONLNd
  7707. ´HTq(p6Macintosh Volume°dONLNd
  7708. ªHqTt)Y °dONLNd
  7709. ºHtT⁄)HI. The drawing environment consists of, among other things, the size and°dONLNd T`°(|6location of the graphics pen, °dONLNd #T°`⁄)â=the foreground and background colors to use when something is°dONLNd a`lÖ(à6Qdrawn, the pattern to use, the region to clip all drawing to, and the portion of °dONLNd ≤`Öl⁄(à£a pixel image that°dONLNd ≈lx*(î6the 
  7710. °dONLNd …l*x`)    CGrafPort
  7711. °dONLNd “l`x    )6& logically exists in. Any initialized 
  7712. °dONLNd ¯l    x?)©    CGrafPort
  7713. °dONLNd l?xQ)6 or 
  7714. °dONLNd lQxÅ)GrafPort
  7715. °dONLNd
  7716. lÅx⁄)0 can be set as the°dONLNd  xÑ=(†6current °dONLNd (x=Ñí)%port through the 
  7717. °dONLNd 9xíѬ)U_SetPort
  7718. °dONLNd Ax¬Ñ⁄)0: routine. The current port is a set of parameters that are°dONLNd |ÑêÛ(¨6-implicitly passed to most QuickDraw routines. ¡4¡˘
  7719. **2) of 51)Á2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ!*◊#ˇ ˇˇˇˇ#◊ 
  7720. IR,Times
  7721. .+Z-Developer Support Center(-Ï
  7722. March 1992 /X/
  7723. °dONLNd)<5 (QZ)The most important reason to build a new ,
  7724. Courier
  7725. °dONLNd)) 5A)œ    CGrafPort
  7726. °dONLNd2)A5ß)6 when you draw off °dONLNdE)ß5˛)fscreen rather than°dONLNdX5<Aí(]Zusing an existing 
  7727. °dONLNdj5íA»)V    CGrafPort
  7728. °dONLNds5»Aë)6) is so that switching between drawing to °dONLNdú5ëA˛)…an off-screen graphics°dONLNd≥A<MÉ(iZAenvironment and drawing to one or more windows (each of which is °dONLNdÙAÉM¿(i° an extended 
  7729. °dONLNdA¿M)=GrafPort
  7730. °dONLNdAM˛)0 or
  7731. °dONLNd M<Yr(uZ    CGrafPort
  7732. °dONLNdMrY)6% structure) on the screen is very eas°dONLNd:MY)¶y°dONLNd;MYü). Some people use just one 
  7733. °dONLNdVMüY’)Ç    CGrafPort
  7734. °dONLNd_M’Yÿ)6 °dONLNd`MÿY˛)to share°dONLNdiY<eß(ÅZIbetween on-screen and off-screen graphics environments, and switch their 
  7735. °dONLNd≤YßeÀ(Å≈PixMap
  7736. °dONLNd∏YÀe˛)$  structures°dONLNdƒe<qæ(çZto switch between drawing °dONLNdfieæq˙)Ç@on screen and drawing off screen. That does work, but if the off°dONLNde˙q˛(ç-°dONLNdq<}T(ôZ2screen and on-screen graphics environments have a °dONLNdQqT}Ö(ôr
  7737. different 
  7738. °dONLNd[qÖ}Ø)1clipRgn
  7739. °dONLNdbqØ}º)*, 
  7740. °dONLNddqº}‡)
  7741. visRgn
  7742. °dONLNdjq‡}˛)$, pen°dONLNdp}<âÇ(•Zcharacteristic, 
  7743. °dONLNdÄ}Çâ≤)FportRect
  7744. °dONLNdà}≤â∑)08, or any other characteristics that are different, then °dONLNd¿}∑â˛(•’
  7745. those must be°dONLNdŒâ<ï)(±Z3switched at that time too. If you instead create a 
  7746. °dONLNdâ)ï_)Ì    CGrafPort
  7747. °dONLNd
  7748. â_ïÅ)6 that’s °dONLNdâÅï˛)"dedicated to one graphics°dONLNd,ï<°‰(ΩZ#environment, then a simple call to 
  7749. °dONLNdO)®_SetPort
  7750. °dONLNdWï°˛)01 effectively switches all these things for you at°dONLNdâ°<≠∫(…ZGonce. That’s why every window on the screen comes with its own port. A °dONLNd–°∫≠˛(…ÿsimple call to
  7751. °dONLNdfl≠<πl(’Z_SetPort
  7752. °dONLNdÁ≠lπ%)0& switches between the characteristics °dONLNd
  7753. ≠%π˛)π&of each window even if each window has°dONLNd4π<≈(·Z,radically different drawing characteristics.°dONLNda—<›Q*The 
  7754. °dONLNde—Q›á)    CGrafPort
  7755. °dONLNdn—á›Ú)6 data structure is more °dONLNdÜ—Ú›˛)k5completely described in the “Color QuickDraw” chapter°dONLNdº›<ÈI(Zof °dONLNdø›IÈù)
  7756. Inside Macintosh °dONLNd–›ùÈ•)TV°dONLNd—›§È)olume V, pages 49 °dONLNd„›È˛)\2through 52, and in the “Graphics Overview” chapter°dONLNdÈ<ıI(Zof °dONLNdÈIıù)
  7757. Inside Macintosh °dONLNd*Èùı•)TV°dONLNd+ȧı\)$olume VI, pages 16-12 through 16-13.°dONLNdP<
  7758. Ä()Z
  7759. The PixMap°dONLNd[<%˜*'A pixel image alone is just a formless °dONLNdǘ%A)ª
  7760. blob of memor°dONLNdèA%G)Jy°dONLNdêF%⁄). Pixel maps, defined by the 
  7761. °dONLNd≠⁄%˛)îPixMap
  7762. °dONLNd¥%<1m(MZ structure, °dONLNdø%m1˛)1Qdescribe pixel images, giving them a form and structure that’s suitable for Color°dONLNd1<=d(YZ4QuickDraw to draw into them and copy from them. The 
  7763. °dONLNdE1d=à(YÇPixMap
  7764. °dONLNdK1à=Ω)$  structure °dONLNdV1Ω=˛)5
  7765. tells you the°dONLNdd=<IK(eZ6dimensions and location in memory of the pixel image, °dONLNdö=KI˛(ei$its coordinate system, and the depth°dONLNdøI<U¯(qZ%and format of the pixels. Pixel maps °dONLNd‰I¯U˛)º5that describe indexed-color pixel images additionally°dONLNdU<aˆ(}Z^describe the colors that are represented by the values of the pixels in the pixel image. This °dONLNdxUˆa˛(}is°dONLNd{a<m:(âZ6done through the color table, also known as the color °dONLNd±a:m˛)˛'look-up table or CLUT. Color tables are°dONLNdŸm<yÁ(ïZ%attached to pixel maps through their 
  7766. °dONLNd˛mÁy)´pmTable
  7767. °dONLNdmyk)* field. Direct-color °dONLNdmky˛)Zpixel images have pixel values°dONLNd9y<Öô(°ZLthat describe their own colors, and so color tables aren’t needed for those.°dONLNdÜë<ùS*The 
  7768. °dONLNdäëSùw)PixMap
  7769. °dONLNdêëwù˜)$ structure is described in °dONLNd´ë˜ù™)Ä!the “Color QuickDraw” chapter of °dONLNdÃë™ù˛)≥Inside Macintosh°dONLNd›ù<©D(≈ZV°dONLNdfiùC©c)olume °dONLNd‰ùc©k) V°dONLNdÂùj©Ÿ), pages 52 through 55, °dONLNd¸ùŸ©¨)o*and in the “Graphics Overview” chapter of °dONLNd    &ù¨©˛)”Inside Macintosh°dONLNd    7©<µD(—ZV°dONLNd    8©Cµv)
  7770. olume VI, °dONLNd    B©vµ˛)3Opages 16-11 through 16-12. The concept of direct-color and indexed-color pixels°dONLNd    íµ<¡ü(›Zis described in this °dONLNd    ßµü¡˛)cAsame chapter on pages 16-16 through 16-18, and also in the “Color°dONLNd    È¡<Õå(ÈZBQuickDraw” chapter of the same volume on pages 17-4 through 17-10.°dONLNd
  7771. ,Ÿ<ÂÖ* The GDevice°dONLNd
  7772. 8Ò<˝⁄*!Graphics devices, defined by the 
  7773. °dONLNd
  7774. YÒ⁄˝)ûGDevice
  7775. °dONLNd
  7776. `Ò˝)* °dONLNd
  7777. aÒ˝˛)3structure, describe color environments. They’re the°dONLNd
  7778. ï˝<    ’(%ZTmost misunderstood data structure when it comes to off-screen graphics environments °dONLNd
  7779. È˝’    ˛(%Û    for three°dONLNd
  7780. Û    <U(1Z;major reasons: first, they’re not originally documented as °dONLNd .    U˛(1s!being relevant to humans; second,°dONLNd P<!i(=ZBthey look as though they’re only for screens; and third, it looks °dONLNd íi!˛(=áas though color tables describe°dONLNd ≤!<-ƒ(IZcolor environments. We can °dONLNd Õ!ƒ-˛)à?dispose of these myths here: graphics devices are documented as°dONLNd
  7781. -<9Ì(UZ`being useful to humanity in this Note at least; they’re critically important for both on-screen °dONLNd m-Ì9˛(U and°dONLNd q9<E1(aZ.off-screen drawing; and color tables describe °dONLNd ü91EŒ)ıthe colors in pixel images, °dONLNd ª9ŒE›)ùnot°dONLNd æ9›E˛) color°dONLNd ≈E<QÄ(mZ
  7782. environments.°dONLNd ”]<i/*2What’s all this about color environments? In theor°dONLNd
  7783. ]/i5)Ûy°dONLNd
  7784. ]4i<), °dONLNd
  7785. ]<i˛)*there are virtually three hundred trillion°dONLNd
  7786. 3i<uW(ëZ9colors available with Color QuickDraw through the 48-bit 
  7787. °dONLNd
  7788. liWuá(ëuRGBColor
  7789. °dONLNd
  7790. tiáuŸ)0 record. In realit°dONLNd
  7791. ÜiŸufl)Ry°dONLNd
  7792. áifiu˛), there°dONLNd
  7793. èu<ÅC(ùZ8are never this many colors available, and in fact there °dONLNd
  7794. «uCŞ(ùa"might be only two. Color QuickDraw°dONLNd
  7795. ÍÅ<çv(©ZFmaps the theoretical color that you specify to the pixel value of the °dONLNd0Åvç˛(©îclosest available color in the ¡X¡
  7796. (÷Z2QD 13 - Principia Off-Screen Graphics Environments(÷ˇ3) of 51(ÏZM.QD.PrincipiaOffScreenˇA¶◊#ˇ ˇˇˇˇ#◊ 
  7797. IR,Times
  7798. .+6-Macintosh Technical Notes /4/˘
  7799. °dONLNd)O*@current color environment. This can be done with a color table, °dONLNd@O)⁄(Embut that’s not very efficient.°dONLNd_)5@(Q6Finding °dONLNdg)@5€)("the closest available color to an ,
  7800. Courier
  7801. °dONLNdâ)€5 )õRGBColor
  7802. °dONLNdë) 5⁄)0, in a color table means searching the entire°dONLNdæ5Aq(]6color table for that °dONLNd”5qA⁄)YKone closest color. If that’s done just once, then performance isn’t much of°dONLNdAMS(i6Dan issue, but if it’s done many times, the performance hit could be °dONLNdcASM⁄(iqsignificant. A very bad case°dONLNdÄMYD(u6 of this is 
  7803. °dONLNdãMDYz),    _CopyBits
  7804. °dONLNdîMzYé)6;, where every pixel value in the source image is converted °dONLNdœMéY™(u¨to an 
  7805. °dONLNd’M™Y⁄)RGBColor
  7806. °dONLNdfiYe(Å62by looking it up in the color table of the source 
  7807. °dONLNdYe&)ÍPixMap
  7808. °dONLNdY&e:)$. If °dONLNdY:e⁄)"the color table of the destination
  7809. °dONLNd>eq<(ç6PixMap
  7810. °dONLNdDe<qª)$O had to be searched to find the closest available color for every pixel in the °dONLNdìeªq⁄(çŸsource
  7811. °dONLNdöq}<(ô6PixMap
  7812. °dONLNd†q<}∂)$, then the performance of °dONLNd∫q∂}J)zeven the most straightforward 
  7813. °dONLNdÿqJ}Ä)î    _CopyBits
  7814. °dONLNd·qÄ}⁄)6 call could be a lot°dONLNdˆ}ââ(•6slower than it has to be.°dONLNdï°fl*+To avoid this performance hit, the current 
  7815. °dONLNd;ïfl°    )«GDevice
  7816. °dONLNdBï    °F)*
  7817.  provides an °dONLNdOïF°⁄)=inverse table and a device type°dONLNdo°≠å(…6Lwhich are used to determine the available set of colors. Inverse tables are °dONLNdª°å≠⁄(…™anticolor tables.°dONLNdÕ≠π€(’6(Where color tables give you a color for °dONLNdı≠€π⁄)√4a given pixel value, inverse tables give you a pixel°dONLNd*π≈‚(·6+value for a given color. Every conceivable °dONLNdUπ‚≈⁄) 3color table has a corresponding conceivable inverse°dONLNdâ≈—B(Ì6>table, just as every positive real number has a corresponding °dONLNd«≈B—⁄(Ì`negative real number, or every°dONLNdÊ—›m(˘6BMr. Spock has a corresponding Mr. Spock with a goatee. The device °dONLNd(—m›⁄(˘ãtype specifies whether°dONLNd?›ÈÛ(6.the color environment uses the indexed-color, °dONLNdm›ÛÈ÷)€1fixed-color, or direct-color model. In the direct°dONLNdû›÷È⁄)„-°dONLNdüÈık(6color model, the °dONLNd∞Èkı—)Sinverse table is empt°dONLNd≈È—ı◊)fy°dONLNdΔÈ÷ı⁄)4. Only the indexed-color and direct-color models are°dONLNd˚ıÉ(6described in this Note.°dONLNd
  7818. p*@When you specify a color in an indexed-color environment, Color °dONLNdS
  7819. p⁄(5éQuickDraw takes the
  7820. °dONLNdg%H(A6RGBColor
  7821. °dONLNdoH%ê)0I specification and converts it into a value that can be used as an index °dONLNd∏ê%⁄(AÆinto the inverse°dONLNd…%1{(M6table of the current 
  7822. °dONLNdfi%{1•)cGDevice
  7823. °dONLNdÂ%•1$)*. To do this conversion, °dONLNd˛%$1⁄)!Color QuickDraw takes the top few°dONLNd 1=j(Y6Esignificant bits of each color component and combines them into part °dONLNde1j=⁄(Yàof a 16-bit word, blue°dONLNd|=Iá(e6Vbits in the least significant bits, green bits right above it, and the red bits right °dONLNd“=áI⁄(e•above green bits.°dONLNd‰IUµ(q6ZAny unused bits are in the most significant bits of the 16-bit word. The resulting 16-bit °dONLNd>IµU⁄(q”word is°dONLNdFUa~(}6used as an index into °dONLNd\U~a⁄)fLthe inverse table. The value in the inverse table at that index is the pixel°dONLNd©amÃ(â6'value which best represents that color °dONLNd–aÃm⁄)¥7in the current color environment. The number of bits of°dONLNd    my∂(ï6 each component that are used is °dONLNd    (m∂y⁄)û;determined by what’s called the “resolution” of the inverse°dONLNd    dyÖ9(°69table. Almost always, the resolution of an inverse table °dONLNd    ùy9Ö⁄(°Wis four bits, meaning the most°dONLNd    ºÖëw(≠6Lsignificant four bits of each component are used to form the index into the °dONLNd
  7824. Öwë⁄(≠ïinverse table. Figure°dONLNd
  7825. ëùE(π61 shows °dONLNd
  7826. &ëEùo)-how an 
  7827. °dONLNd
  7828. -ëoùü)*RGBColor
  7829. °dONLNd
  7830. 5ëüù⁄)0? record is converted to an index into an inverse table when the°dONLNd
  7831. uù©¨(≈6!inverse-table resolution is four.†ƒ°d
  7832. ONLNfZ
  7833. ‘DaÈ"‘D†ƒ°d
  7834. ONLNf:"aȆƒ°d
  7835. ONLNf`°d$MOR28◊û‡=q&T¢aEaEa¢^¢^BTBTEaEˇˇˇˇˇˇˇˇˇˇˇˇ    1Qü^B    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊û‡ßˇˇˇˇˇˇˇˇˇˇˇˇ    1R†]´    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊®‡±ˇˇˇˇˇˇˇˇˇˇˇˇ    1R™]µ    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊≤‡ªˇˇˇˇˇˇˇˇˇˇˇˇ    1R¥]ø    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊º‡≈ˇˇˇˇˇˇˇˇˇˇˇˇ    1Ræ]…    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊Δ‡œˇˇˇˇˇˇˇˇˇˇˇˇ    1R»]”    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊–‡Ÿˇˇˇˇˇˇˇˇˇˇˇˇ    1R“]›    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊⁄‡„ˇˇˇˇˇˇˇˇˇˇˇˇ    1R‹]Á    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊‰‡Ìü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1RÊ]Ò    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊Ó‡˜ˇˇˇˇˇˇˇˇˇˇˇˇ    1R]˚    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊¯‡ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1R˙]    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊‡ ˇˇˇˇˇˇˇˇˇˇˇˇ    1R]    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊ ‡ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1R]    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊‡ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1R]#    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊ ‡)ˇˇˇˇˇˇˇˇˇˇˇˇ    1R"]-    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊*‡3ˇˇˇˇˇˇˇˇˇˇˇˇ    1R,]7    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28◊4‡=ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1R6]A    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR2 Xπ9‘9ˇˇ†åqF8P@P<F@F8P<"4;†ç°dMOR2°d$MOR2 Xπ.‘.ˇˇ†åqF-P5P1F5F-P1"40†ç°dMOR2°d$MOR2 Xπ$‘$ˇˇ†åqF#P+P'F+F#P'"4&†ç°dMOR2°d$MOR2 Xπ‘ˇˇ†åqFP!PF!FP"4†ç°dMOR2°d$MOR2 X󑡡†åqFPPFFP"9†ç°dMOR2°d$MOR2 X󑡡†åqFP
  7836. P    F
  7837. FP    "9†ç°dMOR2°d$MOR2 X󸑸ˇˇ†åqF˚PPˇFF˚Pˇ"˛9†ç°dMOR2°d$MOR2 XóÚ‘Úˇˇ†åqFÒP˘PıF˘FÒPı"Ù9†ç°dMOR2°d$MOR2 Xrˑˡˇ†åqFÁPÔPÎFÔFÁPÎ"ÌÍ^†ç°dMOR2°d$MOR2 Xrfi‘fiˇˇ†åqF›PÂP·FÂF›P·"̇^†ç°dMOR2°d$MOR2 Xr‘‘‘ˇˇ†åqF”P€P◊F€F”P◊"Ì÷^†ç°dMOR2°d$MOR2 Xr ‘ ˇˇ†åqF…P—PÕF—F…PÕ"ÌÃ^†ç°dMOR2°ñ†òˇˇˇˇˇˇ
  7838. ‘‡,ç•ç•°dONLNdˇˇ+‹red†ô†ó°d$MOR28fΔoe
  7839. ‘DaÈq&„ mm Ì Ìj„j„mmˇˇˇˇˇˇˇˇˇˇˇˇ    1‡«Ìj    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28fΔoœˇˇˇˇˇˇˇˇˇˇˇˇ    1·»Ï”    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28f–oŸˇˇˇˇˇˇˇˇˇˇˇˇ    1·“Ï›    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28f⁄o„ˇˇˇˇˇˇˇˇˇˇˇˇ    1·‹ÏÁ    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28f‰oÌü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1·ÊÏÒ    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28fÓo˜ˇˇˇˇˇˇˇˇˇˇˇˇ    1·Ï˚    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28f¯oˇˇˇˇˇˇˇˇˇˇˇˇ    1·˙Ï    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28fo ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1·Ï    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28f oˇˇˇˇˇˇˇˇˇˇˇˇ    1·Ï    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28foˇˇˇˇˇˇˇˇˇˇˇˇ    1·Ï#    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28f o)ˇˇˇˇˇˇˇˇˇˇˇˇ    1·"Ï-    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28f*o3ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1·,Ï7    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28f4o=ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1·6ÏA    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28f>oGˇˇˇˇˇˇˇˇˇˇˇˇ    1·@ÏK    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28fHoQü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1·JÏU    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28fRo[ˇˇˇˇˇˇˇˇˇˇˇˇ    1·TÏ_    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28f\oeˇˇˇˇˇˇˇˇˇˇˇˇ    1·^Ïi    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28äÓìçq&ÚïïÚÚííïïˇˇˇˇˇˇˇˇˇˇˇˇ    1Ôí    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28äÓì˜ˇˇˇˇˇˇˇˇˇˇˇˇ    1˚    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28ä¯ìü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1˙    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28äì ˇˇˇˇˇˇˇˇˇˇˇˇ    1    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28ä ìü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28äìˇˇˇˇˇˇˇˇˇˇˇˇ    1#    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28ä ì)ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1"-    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28ä*ì3ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1,7    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28ä4ì=ˇˇˇˇˇˇˇˇˇˇˇˇ    16A    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28ä>ìGˇˇˇˇˇˇˇˇˇˇˇˇ    1@K    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28äHìQü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1JU    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28äRì[ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1T_    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28ä\ìeü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1^i    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28äfìoü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1hs    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28äpìyˇˇˇˇˇˇˇˇˇˇˇˇ    1r}    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28äzìɡˇˇˇˇˇˇˇˇˇˇˇ    1|á    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28äÑì硡ˇˇˇˇˇˇˇˇˇˇ    1Üë    ˇˇˇˇˇˇˇˇ8°dMOR2°ñ†òˇˇˇˇˇˇ
  7840. ¯0T°dONLNdˇˇ+#$green†ô†ó°ñ†ò
  7841. X'|°dONLNdˇˇ++#blue†ô†ó°d$MOR28≠∂µ
  7842. ‘DaÈq&*7Ω7Ω744∫*∫*Ω7Ωˇˇˇˇˇˇˇˇˇˇˇˇ    1'4∫    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠∂ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1(3#    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠ ∂)ˇˇˇˇˇˇˇˇˇˇˇˇ    1("3-    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠*∂3ˇˇˇˇˇˇˇˇˇˇˇˇ    1(,37    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠4∂=ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1(63A    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠>∂Gü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1(@3K    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠H∂Qˇˇˇˇˇˇˇˇˇˇˇˇ    1(J3U    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠R∂[ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1(T3_    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠\∂eˇˇˇˇˇˇˇˇˇˇˇˇ    1(^3i    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠f∂oü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1(h3s    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠p∂yˇˇˇˇˇˇˇˇˇˇˇˇ    1(r3}    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠z∂Éü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1(|3á    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠Ñ∂çü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1(Ü3ë    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠é∂óü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1(ê3õ    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠ò∂°ü˚ü˚ü˚ü˚ü˚ü˚    U"UàUUà1(ö3•    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠¢∂´ˇˇˇˇˇˇˇˇˇˇˇˇ    1(§3Ø    ˇˇˇˇˇˇˇˇ8°dMOR2°d$MOR28≠¨∂µˇˇˇˇˇˇˇˇˇˇˇˇ    1(Æ3π    ˇˇˇˇˇˇˇˇ8°dMOR2°ñ†òˇˇˇˇˇˇ
  7843. ·nÌì°dONLNdˇˇ(Ín=$1234†ô†ó°ñ†ò
  7844. ñª°dONLNdˇˇ+($=$5678†ô†ó°ñ†ò
  7845. (æ4ȰdONLNdˇˇ+(#=$9ABC†ô†ó°ñ†ò
  7846. RF^k°dONLNdˇˇ([F=$0159†ô†ó°ñ†ò
  7847. Nü
  7848. °dONLNdˇˇ( NRGBColor
  7849. °dONLNdˇˇ)0 record†ô†ó°ñ†ò
  7850. Ÿú9 
  7851. `°dONLNdˇˇ+{†ô†ó°ñ†ò
  7852. RD^ù
  7853. °dONLNdˇˇ([DInverse table index†ô†ó†ƒ°d
  7854. ONLNf.
  7855. IR°dONLNd
  7856. óZ<f∂+'>Figure 1  Conversion of RGBColor Record to Inverse-Table Index°dONLNd
  7857. ÷r~∂(ö6The same process is used when 
  7858. °dONLNd
  7859. Ùr∂~Ï)û    _CopyBits
  7860. °dONLNd
  7861. ˝rÏ~√)6. is called with an indexed-color destination. °dONLNd +r√~⁄)◊Each°dONLNd 0~äµ(¶6#pixel in the source pixel image is °dONLNd S~µä)ùconverted to an 
  7862. °dONLNd c~ä3)NRGBColor
  7863. °dONLNd k~3ä⁄)0# either by doing a table look-up of°dONLNd èäñΩ(≤6Rthe source pixel map’s color table if the source pixel image uses indexed colors, °dONLNd ·äΩñ⁄(≤€or by ¡4¡˘
  7864. (÷64) of 51)Á2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ°¿bu
  7865. /M_pd where{pop}{°¿#userdict begin
  7866. /M_d{M_pd begin}bind def/M_pd dup 24 dict def
  7867. end load begin
  7868. /bdf{bind def}bind def/xdf{exch def}bdf
  7869. /mtx matrix def/M_M matrix def/M_Q matrix def/pop4{pop pop pop pop}bdf
  7870. /M_n{gsave M_Q currentmatrix pop M_M astore aload setmatrix newpath}bdf/M_q{M_Q setmatrix}bdf
  7871. /M_g{grestore}bdf/M_m{moveto}bdf/M_b{curveto}bdf/M_l{lineto}bdf/M_f{eofill}bdf
  7872. /M_s{setlinewidth stroke}bdf/M_c{eoclip currentpoint newpath moveto}bdf
  7873. /M_o{/@1 xdf/@2 xdf/@3 xdf/@4 xdf
  7874. mtx currentmatrix pop
  7875. @2 @4 add 2 div @1 @3 add 2 div translate
  7876. @2 @4 sub @1 @3 sub scale
  7877. 0 0 0.5 0 360 arc M_c
  7878. mtx setmatrix}bdf
  7879. /M_r{2. div/@1 xdf/@3 xdf/@2 xdf/@5 xdf/@4 xdf
  7880. @2 @4 sub 2. div dup @1 lt{/@1 xdf}{pop}ifelse
  7881. @3 @5 sub 2. div dup @1 lt{/@1 xdf}{pop}ifelse
  7882. @2 @4 add 2. div @5 moveto
  7883. @2 @5 @2 @3 @1 arcto pop4
  7884. @2 @3 @4 @3 @1 arcto pop4
  7885. @4 @3 @4 @5 @1 arcto pop4
  7886. @4 @5 @2 @5 @1 arcto pop4}bdf
  7887. /M_x{gsave
  7888. @2 @1 translate
  7889. @4 @2 sub @5 2 get @5 0 get sub div
  7890. @3 @1 sub @5 3 get @5 1 get sub div
  7891. scale
  7892. @5 0 get neg @5 1 get neg translate
  7893. M_M currentmatrix aload pop
  7894. grestore
  7895. }bdf
  7896. end
  7897. °¿ }ifelse
  7898. bn
  7899. †ø°¿M_d
  7900. °¿currentpoint/@1 xdf/@2 xdf
  7901. °¿end
  7902. †ø°¿M_d
  7903. °¿currentpoint/@3 xdf/@4 xdf
  7904. °¿/@5[65 88 486 229]def
  7905. °¿M_x
  7906. °¿end
  7907. †ø°¿M_d
  7908. °¿M_M astore pop
  7909. °¿end
  7910. †ø◊#ˇ ˇˇˇˇ#◊ 
  7911. IR,Times
  7912. .+Z-Developer Support Center(-Ï
  7913. March 1992 /X/
  7914. °dONLNd<)Å(EZexpanding the °dONLNdÅ)’)Epixel value to an ,
  7915. Courier
  7916. °dONLNd ’))TRGBColor
  7917. °dONLNd()˛)05 record if the source pixel image uses direct colors.°dONLNd^)<5}(QZThe resulting 
  7918. °dONLNdl)}5≠)ARGBColor
  7919. °dONLNdt)≠5&)0 is then used to look up a °dONLNdè)&5˛)y/pixel value in the inverse table of the current
  7920. °dONLNdø5<Af(]ZGDevice
  7921. °dONLNdΔ5fA~)*?, and this pixel value is put into the destination pixel image.°dONLNdM<YÅ(uZIf you specify °dONLNdMÅYê)E:a color in a direct-color environment, then the resulting 
  7922. °dONLNdOMêY¿(uÆRGBColor
  7923. °dONLNdWM¿Y˛)0
  7924.  is converted°dONLNdeY<eR(ÅZto a °dONLNdjYRe˛)Tdirect pixel value by the processes that are shown on pages 17-6 through 17-9 of the°dONLNdøe<qœ(çZ“Color QuickDraw” chapter of °dONLNd‹eœq#)ìInside Macintosh °dONLNdÌe#q+)TV°dONLNdÓe*qZ)    olume VI.°dONLNd¯}<â[(•ZUsuall°dONLNd˛}[âa)y°dONLNdˇ}`âK)2, inverse-table look-up involves an extra step to °dONLNd1}Kâ˛)Î$find what are called “hidden colors”°dONLNdVâ<ïz(±ZFusing proprietary information that’s stored at the end of the inverse °dONLNdúâzï˛(±òtable. With an inverse-table°dONLNdπï<°à(ΩZFresolution of four, only 16 shades of any particular component can be °dONLNdˇïà°˛(Ω¶distinguished, and that’s°dONLNd°<≠
  7925. (…Z*often not enough. An inverse table with a °dONLNdC°
  7926. ≠˛)Œ4resolution of five is much larger, but it still only°dONLNdx≠<π!(’Z-gives you 32 shades of any component. Hidden °dONLNd•≠!π˙)Â-colors are looked up after the normal inverse°dONLNd“≠˙π˛)Ÿ-°dONLNd”π<≈â(·Ztable look-up to °dONLNd‰πâ≈˛)MNgive a much more accurate representation of the specified color in the current°dONLNd3≈<—¸(ÌZ)color environment than the inverse-table °dONLNd\≈¸—˛)¿2look-up alone can produce. Sometimes, most notably°dONLNdè—<›s(˘Z?when the arithmetic transfer modes are used or if dithering is °dONLNdŒ—s›˛(˘ëused, the hidden colors are°dONLNdÍ›<Èd(Zignored.°dONLNdÛı<*(When a new color table is assigned to a 
  7927. °dONLNdı&)ΔPixMap
  7928. °dONLNd!ı&–)$% or when its existing color table is °dONLNdFı–˛)™    modified,°dONLNdP<
  7929. !()Z.then a new corresponding inverse table should °dONLNd~!
  7930. â)Âbe generated for the 
  7931. °dONLNdìâ
  7932. ≥)hGDevice
  7933. °dONLNdö≥
  7934. ˛)* that’ll be used°dONLNd´
  7935. <(5Z+when drawing into that environment. Normall°dONLNd÷
  7936. )Ÿy°dONLNd◊
  7937. †), this happens automatically °dONLNdÙ
  7938. †˛)Üwithout you having°dONLNd<%º(AZOto do any more than inform Color QuickDraw of the change. This is described in °dONLNdVº%˛(A⁄more detail in°dONLNdf%<1O(MZ:“Changing the Off-Screen Color Table”  later in this Note.°dONLNd°=<I™*EGraphics devices are documented in the “Graphics Devices” chapter of °dONLNdÊ=™IÕ(e»Inside °dONLNdÌ=ÕI˛)#    Macintosh°dONLNd˜I<UD(qZV°dONLNd¯ICUu)<olume VI which supersedes the “Graphics Devices” chapter of °dONLNd4IuUÀ(qìInside Macintosh °dONLNdEIÀU”)VV°dONLNdFI“UÛ)olume °dONLNdLIÛU˚)!V°dONLNdMI˙U˛).°dONLNdOU<a^(}Z:They’re also discussed in the “Graphics Overview” chapter °dONLNdâU^am(}|of °dONLNdåUma≈)Inside Macintosh °dONLNdùU≈aÕ)XV°dONLNdûUÃa˛)    olume VI,°dONLNd®a<mP(âZ7pages 16-13 through 16-14. The inverse-table mechanism °dONLNdflaPm˛(ân#is described in the “Color Manager”°dONLNdm<yn(ïZ chapter of °dONLNdmny¬)2Inside Macintosh °dONLNdm¬y )TV°dONLNd m…yÈ)olume °dONLNd&mÈyÒ) V°dONLNd'myÙ),°dONLNd(mÛyg) pages 137 through 139.°dONLNd@Ö<ë¢(≠ZAll Together Now°dONLNdQù<©ø*VThere are a lot of different ways to put the three structures together, and this Note °dONLNdßùø©˛(≈›
  7939. discusses the°dONLNdµ©<µˆ(—Z'architecture that’s shown in Figure 2. °dONLNd‹©ˆµ˛)∫4This architecture is  useful when you want a simple,°dONLNd    µ<¡ˇ(›Z(atomic, off-screen graphics environment. ¡X¡
  7940. *˘2QD 13 - Principia Off-Screen Graphics Environments(÷ˇ5) of 51(ÏZM.QD.PrincipiaOffScreenˇ‹◊#ˇ ˇˇˇˇ#◊ 
  7941. IR,Times
  7942. .+6-Macintosh Technical Notes /4/˘†ƒ°d
  7943. ONLNfZ
  7944. <e+»"<e†ƒ°d
  7945. ONLNf:"+Ƞġd
  7946. ONLNf`°d$MOR28HZ¢¥q&Oh≠Δ≠Δ≠h™h™√O√OΔ≠Δfl˙fl˙fl˙fl˙fl˙fl˙    à à"1Le™√    ˇˇˇˇˇˇˇˇ8°dMOR2°ñ†òˇˇˇˇˇˇ
  7947. <pH∏,
  7948. Courier
  7949. ÔcÔc°dONLNdˇˇ+:    CGrafPort†ô†ó°d$MOR28H΢C
  7950. <e+»q&O˘≠U≠U≠˘™˘™ROROU≠Ufl˙fl˙fl˙fl˙fl˙fl˙    à à"1Lˆ™R    ˇˇˇˇˇˇˇˇ8°dMOR2°ñ†òˇˇˇˇˇˇ
  7951. <H@°dONLNdˇˇ)òGDevice†ô†ó°d$MOR28Δ§ ¸
  7952. <e+»q&Õ≤+++≤(≤( Õ Õ+fl˙fl˙fl˙fl˙fl˙fl˙    à à"1 Ø(     ˇˇˇˇˇˇˇˇ8°dMOR2°ñ†òˇˇˇˇˇˇ
  7953. ∫≈Δı°dONLNdˇˇ(ƒ≈PixMap†ô†ó°d$MOR28Zdf™ˇˇˇˇˇˇ
  7954. <e+»    1`ql∑°dMOR2°ñ†ò
  7955. `ql∑°dONLNdˇˇ(jq
  7956. portPixMap†ô†ó°d$MOR28Z˚f3ˇˇˇˇˇˇ
  7957. <e+»1`l@°dMOR2°ñ†ò
  7958. `l@°dONLNdˇˇ)ógdITable†ô†ó°d$MOR28~ä,ˇˇˇˇˇˇ
  7959. <e+»1Ñê9°dMOR2°ñ†ò
  7960. Ñê9°dONLNdˇˇ+$gdPMap†ô†ó°d$MOR28∏Èˇˇˇˇˇˇ
  7961. <e+»1≈ ˆ°dMOR2°ñ†ò
  7962. ≈ ˆ°dONLNdˇˇ(≈pmTable†ô†ó°d$MOR2 X`Æ`ƒˇˇ
  7963. <e+»    ˇˇˇˇˇˇˇˇ"e∫°dMOR2°d$MOR2 X`ƒ∞ƒˇˇ†åq¨Õ∂’∂—¨’¨Õ∂—#L†ç°dMOR2°d$MOR2 XÑ˘Ñ⁄ˇˇ"â·°dMOR2°d$MOR2 XÑ⁄∞⁄ˇˇ†åq¨„∂Î∂Á¨Î¨„∂Á#(†ç°dMOR2°d$MOR28V^j∂q&]lu»u»ulrlr≈]≈]»u»fl˙fl˙fl˙fl˙fl˙fl˙    à à"1Zir≈    ˇˇˇˇˇˇˇˇ8°dMOR2°ñ†òˇˇˇˇˇˇ
  7964. JqVæ°dONLNdˇˇ(Sq
  7965. Inverse Table†ô†ó°d$MOR2 X`5`Zˇˇ†å
  7966. <e+»qb]jgfgb]j]fg"eA!†ç°dMOR2°d$MOR28    mq&#(((#%#%||(fl˙fl˙fl˙fl˙fl˙fl˙    à à"1
  7967.  %|    ˇˇˇˇˇˇˇˇ8°dMOR2°ñ†òˇˇˇˇˇˇ
  7968. ˝-    p°dONLNdˇˇ(- Color Table†ô†ó°d$MOR2 XΡˇ†å
  7969. <e+»q"˜!†ç°dMOR2†ƒ°d
  7970. ONLNf.ˇˇˇˇˇˇ
  7971. IR°dONLNd$80∫(LVAFigure 2  Relationships Between Structures for Off-Screen Drawing°dONLNdB<H—(d6)Notice that there’s no way to get to the 
  7972. °dONLNdk<—H˚)πGDevice
  7973. °dONLNdr<˚H))*
  7974.  from the 
  7975. °dONLNd|<)H_).    CGrafPort
  7976. °dONLNdÖ<_Hû)6, nor is there °dONLNdî<ûH⁄)? a way to get°dONLNd°HT5(p6to the 
  7977. °dONLNd®H5Tk)    CGrafPort
  7978. °dONLNd±HkTô)6
  7979.  from the 
  7980. °dONLNdªHôT√).GDevice
  7981. °dONLNd¬H√Tˇ)*
  7982. , though the 
  7983. °dONLNdœHˇT#)<PixMap
  7984. °dONLNd’H#T√)$" can be found through either one. °dONLNd˜H√TÀ)†Y°dONLNd¯H T⁄)our°dONLNd¸T`—(|6(application must keep track of both the 
  7985. °dONLNd$T—`)π    CGrafPort
  7986. °dONLNd-T`/)6     and the 
  7987. °dONLNd6T/`Y)(GDevice
  7988. °dONLNd=TY`])*.
  7989. °dONLNd?xáõ(£6Building the Blocks
  7990. °dONLNdSìüT*
  7991. As with just °dONLNd`ìTü⁄)<Qabout any algorithm, there are many ways to put the different structures together°dONLNd≤ü´8(«6;that form an off-screen graphics environment. This section °dONLNdÌü8´⁄(«V covers just one way to build the°dONLNd´∑…(”6&architecture that’s shown in Figure 2.°dONLNd5√œù*Building the CGrafPort°dONLNdL€Á.*The 
  7992. °dONLNdP€.Ád)    CGrafPort
  7993. °dONLNdY€dÁ°)6 structure is °dONLNdg€°Áx)=,the easiest one to put together because the 
  7994. °dONLNdì€xÁ¥)◊
  7995. _OpenCPort
  7996. °dONLNdù€¥Á⁄)< routine°dONLNd¶ÁÛ€(6)initializes so many of the fields of the 
  7997. °dONLNdœÁ€Û)√    CGrafPort
  7998. °dONLNdÿÁÛ)6 °dONLNdŸÁÛ⁄)(structure for you. It also allocates and°dONLNdÛˇ(66initializes the structures that are attached to every 
  7999. °dONLNd8Ûˇ>)    CGrafPort
  8000. °dONLNdAÛ>ˇÄ)6, such as the 
  8001. °dONLNdOÛġ§)BvisRgn
  8002. °dONLNdUÛ§ˇ¨)$, 
  8003. °dONLNdWÛ¨ˇ÷)clipRgn
  8004. °dONLNd^Û÷ˇ⁄)*,
  8005. °dONLNd`ˇ H('6grafVars
  8006. °dONLNdhˇH )0) handle, and so forth. Most of these are °dONLNdëˇ ⁄)œ)initialized with values that are fine for°dONLNdª í(36general purposes, but the 
  8007. °dONLNd’ í∂)zvisRgn
  8008. °dONLNd€ ∂Ω)$, 
  8009. °dONLNd› ΩÁ)clipRgn
  8010. °dONLNd‰ ÁÓ)*, °dONLNdÊ Ó)and 
  8011. °dONLNdÍ 3)portRect
  8012. °dONLNdÚ 3⁄)0$ fields should be set to the desired°dONLNd#˜(?6.boundary rectangle of the off-screen graphics °dONLNdE˜#⁄)fl+environment. What follows is an overview of°dONLNdq#/)(K65each of the fields that you have to worry about when °dONLNd¶#)/ê(KGyou’re setting up a 
  8013. °dONLNd∫#ê/Δ)g    CGrafPort
  8014. °dONLNd√#Δ/⁄)6 for°dONLNd»/;u(W6drawing off screen.
  8015. °dONLNd‹GST*
  8016. portPixMap
  8017. °dONLNdÁGÑS˙)lhandle to the off-screen 
  8018. °dONLNdG˙S)vPixMap
  8019. °dONLNdGS&)$. 
  8020. °dONLNdG&Sb)
  8021. _OpenCPort
  8022. °dONLNdGbSf)< °dONLNdGfS⁄)initializes this field to a°dONLNd/SÑ_≠({¢copy of °dONLNd7S≠_¿))the 
  8023. °dONLNd;S¿_‰)PixMap
  8024. °dONLNdAS‰_T)$ that’s attached to the 
  8025. °dONLNdYST_x)pgdPMap
  8026. °dONLNd_Sx_⁄)$ field of the current
  8027. °dONLNdu_ÑkÆ(á¢GDevice
  8028. °dONLNd|_ÆkG)*!. An overview of setting up this 
  8029. °dONLNdù_Gkk)ôPixMap
  8030. °dONLNd£_kk)$ for °dONLNd®_k⁄)drawing off screen°dONLNdªkÑw|(ì¢6is given in  “Building the PixMap” later in this Note.
  8031. °dONLNdÚwÉH(ü6portRect
  8032. °dONLNd˚wÑÉ≤)l
  8033. specifies °dONLNdw≤É⁄).<the rectangular area of the associated pixel image that this
  8034. °dONLNdBÉÑè∫(´¢    CGrafPort
  8035. °dONLNdKÉ∫èΩ)6 °dONLNdLÉΩè⁄)=controls. This field should be set to the desired rectangular ¡4¡˘
  8036. (÷66) of 51)Á2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ°¿bu
  8037. /M_pd where{pop}{°¿#userdict begin
  8038. /M_d{M_pd begin}bind def/M_pd dup 24 dict def
  8039. end load begin
  8040. /bdf{bind def}bind def/xdf{exch def}bdf
  8041. /mtx matrix def/M_M matrix def/M_Q matrix def/pop4{pop pop pop pop}bdf
  8042. /M_n{gsave M_Q currentmatrix pop M_M astore aload setmatrix newpath}bdf/M_q{M_Q setmatrix}bdf
  8043. /M_g{grestore}bdf/M_m{moveto}bdf/M_b{curveto}bdf/M_l{lineto}bdf/M_f{eofill}bdf
  8044. /M_s{setlinewidth stroke}bdf/M_c{eoclip currentpoint newpath moveto}bdf
  8045. /M_o{/@1 xdf/@2 xdf/@3 xdf/@4 xdf
  8046. mtx currentmatrix pop
  8047. @2 @4 add 2 div @1 @3 add 2 div translate
  8048. @2 @4 sub @1 @3 sub scale
  8049. 0 0 0.5 0 360 arc M_c
  8050. mtx setmatrix}bdf
  8051. /M_r{2. div/@1 xdf/@3 xdf/@2 xdf/@5 xdf/@4 xdf
  8052. @2 @4 sub 2. div dup @1 lt{/@1 xdf}{pop}ifelse
  8053. @3 @5 sub 2. div dup @1 lt{/@1 xdf}{pop}ifelse
  8054. @2 @4 add 2. div @5 moveto
  8055. @2 @5 @2 @3 @1 arcto pop4
  8056. @2 @3 @4 @3 @1 arcto pop4
  8057. @4 @3 @4 @5 @1 arcto pop4
  8058. @4 @5 @2 @5 @1 arcto pop4}bdf
  8059. /M_x{gsave
  8060. @2 @1 translate
  8061. @4 @2 sub @5 2 get @5 0 get sub div
  8062. @3 @1 sub @5 3 get @5 1 get sub div
  8063. scale
  8064. @5 0 get neg @5 1 get neg translate
  8065. M_M currentmatrix aload pop
  8066. grestore
  8067. }bdf
  8068. end
  8069. °¿ }ifelse
  8070. bn
  8071. †ø°¿M_d
  8072. °¿currentpoint/@1 xdf/@2 xdf
  8073. °¿end
  8074. †ø°¿M_d
  8075. °¿currentpoint/@3 xdf/@4 xdf
  8076. °¿/@5[88 54 443 293]def
  8077. °¿M_x
  8078. °¿end
  8079. †ø°¿M_d
  8080. °¿M_M astore pop
  8081. °¿end
  8082. †ø¬◊#ˇ ˇˇˇˇ#◊ 
  8083. IR,Times
  8084. .+Z-Developer Support Center(-Ï
  8085. March 1992 /X/
  8086. °dONLNd®)ø(EΔarea °dONLNdø)a) of the off-screen image because ,
  8087. Courier
  8088. °dONLNd%a)ù)¢
  8089. _OpenCPort
  8090. °dONLNd/ù)˛)< doesn’t necessarily°dONLNdD)®5€(QΔinitialize it °dONLNdR)€56)3to this size. Usuall°dONLNdf)65<)[y°dONLNdg);5˛)+, the top-left corner of this rectangle has°dONLNdì5®A~(]Δ/the coordinates (0, 0), but not necessarily so.
  8091. °dONLNd√A<M`(iZvisRgn
  8092. °dONLNd A®M!)lhandle to the region that °dONLNd‰A!M˛)y-specifies the visible area into which you can°dONLNdM®Y«(uΔdraw. 
  8093. °dONLNdM«Y)
  8094. _OpenCPort
  8095. °dONLNd"MYç)<  doesn’t necessarily initialize °dONLNdBMçY˙)äit to the size of the off°dONLNd[M˙Y˛)m-°dONLNd\Y®ea(ÅΔ)screen image, so it should be set to the °dONLNdÖYae˛)π same size and coordinates as the
  8096. °dONLNd¶e®qÿ(çΔportRect
  8097. °dONLNdÆeÿqæ)00 and left at that. This field is more important °dONLNdfieæq˛)Ê for windows°dONLNdÍq®}Ø(ôΔ5because parts of them can be hidden by other windows.
  8098. °dONLNd }<âf(•ZclipRgn
  8099. °dONLNd(}®â!)lhandle to the region that °dONLNdB}!â˛)y-specifies the logical area into which you can°dONLNdpâ®ï∑(±Δdra°dONLNdsâ∑ï¿)w°dONLNdtâøïΔ). 
  8100. °dONLNdvâΔï)
  8101. _OpenCPort
  8102. °dONLNdÄâïÕ)<. initializes it to cover the entire QuickDraw °dONLNdÆâÕï˛)À
  8103. coordinate°dONLNdπï®°#(ΩΔplane. It’s usually a good °dONLNd‘ï#°˛){/idea to set it to the same size and coordinates°dONLNd°®≠Œ(…Δas the 
  8104. °dONLNd °Œ≠˛)&portRect
  8105. °dONLNd°˛≠w)0 to avoid problems if °dONLNd)°w≠ç)ythe 
  8106. °dONLNd-°ç≠∑)clipRgn
  8107. °dONLNd4°∑≠˛)*
  8108.  is scaled or°dONLNdB≠®πÌ(’ΔDtranslated, which causes its signed integer coordinates to overflow °dONLNdÜ≠Ìπ˛(’ and°dONLNdäπ®≈›(·Δ;turn it into an empty region. One of the most common cases °dONLNd≈π›≈˛(·˚of this°dONLNdÕ≈®—{(ÌΔ-occurs when a picture that’s created in this 
  8109. °dONLNd˙≈{—±)”    CGrafPort
  8110. °dONLNd≈±—˘)6 is drawn into °dONLNd≈˘—˛)Ha°dONLNd—®›»(˘Δ@destination rectangle that’s any larger than or translated from °dONLNdT—»›˛(˘Ê the original°dONLNda›®ÈŒ(Δ=picture frame. Everything in the picture, including the clip °dONLNdû›ŒÈ˛(Ï
  8111. region, is°dONLNd©È®ı((Δscaled to fit the destination °dONLNd«È(ı˛)Ä/rectangle. If the clip region covers the entire°dONLNd˜ı®(ΔQuickDraw coordinate °dONLNd ı˛)m1plane, then its coordinates overflow their signed°dONLNd>®
  8112. ()Δinteger bounds, and the °dONLNdV
  8113. ¡)r"clip region becomes logically empt°dONLNdx¡
  8114. «)ßy°dONLNdyΔ
  8115. ˛) . The result°dONLNdÜ
  8116. ®(5Δis that nothing is drawn.°dONLNd†%<1˘(MZ[The CreateOffScreen routine in Listing 1 creates an off-screen graphics environment, given °dONLNd˚%˘1˛(Ma°dONLNd˝1<=J(YZ9boundary rectangle, pixel depth, and color table, and it °dONLNd61J=»(Yhreturns a new off-screen 
  8117. °dONLNdO1»=˛)~    CGrafPort
  8118. °dONLNdY=<IP(eZand 
  8119. °dONLNd]=PIz)GDevice
  8120. °dONLNdd=zIû)*@, along with an error code. The desired pixel depth in bits per °dONLNd§=ûI˛(eºpixel is given in the
  8121. °dONLNd∫I<UZ(qZdepth
  8122. °dONLNdøIZUæ) parameter. If the °dONLNd“IæU˛)d<pixel depth is eight or less, then an indexed-color graphics°dONLNdU<a.(}Z5environment is created and a color table is required °dONLNdDU.aM)Úin the 
  8123. °dONLNdKUMaq)colors
  8124. °dONLNdQUqa˛)$ parameter. If the pixel depth°dONLNdpa<m4(âZ0is 16 or 32 bits per pixel and 32-Bit QuickDraw °dONLNd†a4m˛)¯*is available, then a direct-color graphics°dONLNdÀm<y›(ïZenvironment is created and the 
  8125. °dONLNdÍm›y)°colors
  8126. °dONLNdmyI)$ parameter is °dONLNd˛mIy˛)H"ignored. If 32-Bit QuickDraw isn’t°dONLNd!y<Ö\(°ZAavailable, then a pixel depth of 16 or 32 bits per pixel results °dONLNdby\Ö˛(°z in CreateOffScreen doing nothing°dONLNdÉÖ<ëB(≠Z8more than returning a parameter error. A description of °dONLNdªÖBë˛(≠`&CreateOffScreen is given following the°dONLNd‚ë<ù](πZlisting.°dONLNdΩ<µ∫*MPW Pascal Listing 1
  8127.     °dONLNd    ¡<Ãπ*FUNCTION CreateOffScreen(°dONLNd    À<÷Å*
  8128. A   bounds:         Rect;       {Bounding rectangle of off-screen}°dONLNd    \’<‡«*
  8129. O   depth:          Integer;    {Desired number of bits per pixel in off-screen}°dONLNd    ¨fl<Íê*
  8130. D   colors:         CTabHandle; {Color table to assign to off-screen}°dONLNd    ÒÈ<Ùü*
  8131. G   VAR retPort:    CGrafPtr;   {Returns a pointer to the new CGrafPort}°dONLNd
  8132. 9Û<˛ê*
  8133. D   VAR retGDevice: GDHandle    {Returns a handle to the new GDevice}°dONLNd
  8134. ~˝<x*
  8135.    ): OSErr;°dONLNd
  8136. ã<d*   CONST°dONLNd
  8137. î<&§*
  8138. H      kMaxRowBytes = $3FFE; {Maximum number of bytes in a row of pixels}°dONLNd
  8139. ›/<:Z*   VAR°dONLNd
  8140. ‰9<DÆ*
  8141. J      newPort:     CGrafPtr;     {Pointer to the new off-screen CGrafPort}°dONLNd /C<Nö*
  8142. F      newPixMap:   PixMapHandle; {Handle to the new off-screen PixMap}°dONLNd vM<Xü*
  8143. G      newDevice:   GDHandle;     {Handle to the new off-screen GDevice}°dONLNd æW<b§*
  8144. H      qdVersion:   LongInt;      {Version of QuickDraw currently in use}°dONLNd a<l∏*
  8145. L      savedPort:   GrafPtr;      {Pointer to GrafPort used for save/restore}°dONLNd Tk<vê*
  8146. D      savedState:  SignedByte;   {Saved state of color table handle}°dONLNd ôu<ħ*
  8147. H      bytesPerRow: Integer;      {Number of bytes per row in the PixMap}°dONLNd ‚<äE*
  8148. 5      error:       OSErr;        {Returns error code} ¡X¡
  8149. *02QD 13 - Principia Off-Screen Graphics Environments(÷ˇ7) of 51(ÏZM.QD.PrincipiaOffScreenˇû◊#ˇ ˇˇˇˇ#◊ 
  8150. IR,Times
  8151. .+6-Macintosh Technical Notes /4/˘,
  8152. Courier
  8153.     °dONLNd(1*BEGIN°dONLNd'2*
  8154. 0   (* Initialize a few things before we begin *)°dONLNd71<r*
  8155.    newPort := NIL;°dONLNdJ;F|*
  8156.    newPixMap := NIL;°dONLNd_EP|*
  8157.    newDevice := NIL;°dONLNdtOZr*
  8158.    error := noErr;°dONLNdácnû*N   (* Save the color table’s current state and make sure it isn’t purgeable *)°dONLNd÷mxê*
  8159.    IF colors <> NIL THEN°dONLNdÔwÇO*
  8160.       BEGIN°dONLNd˚Åå
  8161. *
  8162. 1         savedState := HGetState(Handle(colors));°dONLNd-ãñ¬*
  8163. "         HNoPurge(Handle(colors));°dONLNdPï†J*
  8164.  
  8165.       END;°dONLNd[©¥{*G   (* Calculate the number of bytes per row in the off-screen PixMap *)°dONLNd£≥æè*
  8166. K   bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;°dONLNdÔ«“Í**   (* Get the current QuickDraw version *)°dONLNd—‹0*
  8167. 8   error := Gestalt(gestaltQuickdrawVersion, qdVersion);°dONLNdS€Êr*
  8168.    error := noErr;°dONLNdfÔ˙û*N   (* Make sure depth is indexed or depth is direct and 32-Bit QD installed *)°dONLNdµ˘]*
  8169. A   IF (depth = 1) OR (depth = 2) OR (depth = 4) OR (depth = 8) OR°dONLNd˜®*
  8170. P         (((depth = 16) OR (depth = 32)) AND (qdVersion >= gestalt32BitQD)) THEN°dONLNdH
  8171. O*
  8172.       BEGIN°dONLNdT"®*
  8173. P         (* Maximum number of bytes per row is 16,382; make sure within range *)°dONLNd•!,Ù*
  8174. ,         IF bytesPerRow <= kMaxRowBytes THEN°dONLNd“+6m*
  8175.             BEGIN°dONLNd‰5@®*
  8176. P               (* Make sure a color table is provided if the depth is indexed *)°dONLNd5?JΩ*
  8177. !               IF depth <= 8 THEN°dONLNdWIT÷*
  8178. &                  IF colors = NIL THEN°dONLNd~S^î*
  8179. L                     (* Indexed depth and clut is NIL; is parameter error *)°dONLNdÀ]h€*
  8180. '                     error := paramErr;°dONLNdÛgrc*
  8181.             END°dONLNdq|Y*
  8182.  
  8183.          ELSE°dONLNd{Üî*
  8184. L            (* # of bytes per row is more than 16,382; is parameter error *)°dONLNd^ÖêÆ*
  8185.             error := paramErr;°dONLNd}èöE*
  8186.           END°dONLNdáô§;*
  8187.    ELSE°dONLNdè£Æ+*
  8188. 7      (* Pixel depth isn’t valid; is parameter error *)°dONLNd«≠∏ê*
  8189.       error := paramErr;°dONLNd‡¡ÃX*@   (* If sanity checks succeed, then allocate a new CGrafPort *)°dONLNd!À÷ê*
  8190.    IF error = noErr THEN°dONLNd:’‡O*
  8191.       BEGIN°dONLNdFflÍ5*
  8192. 9         newPort := CGrafPtr(NewPtr(SizeOf (CGrafPort)));°dONLNdÄÈÙ≥*
  8193.          IF newPort <> NIL THEN°dONLNd†Û˛m*
  8194.             BEGIN°dONLNd≤˝Í*
  8195. *               (* Save the current port *)°dONLNd›¬*
  8196. "               GetPort(savedPort);°dONLNd&û*N               (* Initialize the new CGrafPort and make it the current port *)°dONLNdO%0¬*
  8197. "               OpenCPort(newPort);°dONLNdr9D£*O               (* Set portRect, visRgn, and clipRgn to the given bounds rect *)°dONLNd¬CNÔ*
  8198. +               newPort^.portRect := bounds;°dONLNdÓMX*
  8199. 0               RectRgn(newPort^.visRgn, bounds);°dONLNdWb∏*
  8200.                 ClipRect(bounds);°dONLNd@kvq*E               (* Initialize the new PixMap for off-screen drawing *)°dONLNdÜuÄ{*
  8201. G               error := SetUpPixMap(depth, bounds, colors, bytesPerRow,°dONLNdŒäÍ*
  8202. *                     newPort^.portPixMap);°dONLNd˘âîÃ*
  8203. $               IF error = noErr THEN ¡4¡˘
  8204. *&8) of 51)Á2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ◊#ˇ ˇˇˇˇ#◊ 
  8205. IR,Times
  8206. .+Z-Developer Support Center(-Ï
  8207. March 1992 /X/,
  8208. Courier
  8209.     °dONLNd<(Ø(DZ                  BEGIN°dONLNd'<2m*
  8210. =                     (* Grab the initialized PixMap handle *)°dONLNdV1<<J*
  8211. 6                     newPixMap := newPort^.portPixMap;°dONLNdçE<P|*@                     (* Allocate and initialize a new GDevice *)°dONLNdŒO<ZÜ*
  8212. B                     error := CreateGDevice(newPixMap, newDevice);°dONLNdY<d™*
  8213.                   END;°dONLNd(m<x*+               (* Restore the saved port *)°dONLNdTw<ÇÊ*
  8214. "               SetPort(savedPort);°dONLNdwÅ<åá*
  8215.             END°dONLNdáã<ñ}*
  8216.  
  8217.          ELSE°dONLNdïï<†“*
  8218.             error := MemError;°dONLNd¥ü<™n*
  8219.  
  8220.       END;°dONLNdø≥<æ;*3   (* Restore the given state of the color table *)°dONLNdÛΩ<»¥*
  8221.    IF colors <> NIL THEN°dONLNd «<“*
  8222. ,      HSetState(Handle(colors), savedState);°dONLNd9€<ÊE*5   (* One Last Look Around The House Before We Go… *)°dONLNdoÂ<π*
  8223.    IF error <> noErr THEN°dONLNdâÔ<˙s*
  8224.       BEGIN°dONLNdï˘<ö*
  8225. F         (* Some error occurred; dispose of everything we allocated *)°dONLNd‹<·*
  8226. !         IF newPixMap <> NIL THEN°dONLNd˛
  8227. <ë*
  8228.             BEGIN°dONLNd<"1*
  8229. 1               DisposCTable(newPixMap^^.pmTable);°dONLNdB!<,'*
  8230. /               DisposPtr(newPixMap^^.baseAddr);°dONLNdr+<6å*
  8231.             END;°dONLNdÉ5<@·*
  8232. !         IF newDevice <> NIL THEN°dONLNd•?<Jë*
  8233.             BEGIN°dONLNd∑I<T^*
  8234. :               DisposHandle(Handle(newDevice^^.gdITable));°dONLNdÚS<^'*
  8235. /               DisposHandle(Handle(newDevice));°dONLNd"]<hå*
  8236.             END;°dONLNd3g<r◊*
  8237.          IF newPort <> NIL THEN°dONLNdSq<|ë*
  8238.             BEGIN°dONLNde{<ÜÎ*
  8239. #               CloseCPort(newPort);°dONLNdâÖ<êˇ*
  8240. '               DisposPtr(Ptr(newPort));°dONLNd±è<öå*
  8241.             END;°dONLNd¬ô<§i*
  8242.           END°dONLNdã<Æ_*
  8243.    ELSE°dONLNd‘≠<∏s*
  8244.       BEGIN°dONLNd‡∑<¬«*
  8245. O         (* Everything’s OK; return refs to off-screen CGrafPort and GDevice *)°dONLNd0¡<û*
  8246.          retPort := newPort;°dONLNdMÀ<÷·*
  8247. !         retGDevice := newDevice;°dONLNdo’<‡n*
  8248.  
  8249.       END;°dONLNdzfl<Í»*
  8250.    CreateOffScreen := error;°dONLNdóÈ<ÙP*
  8251. END;
  8252. °dONLNdúˇ< ü*MPW C Listing 1
  8253.     °dONLNd¨<"∏*L#define kMaxRowBytes 0x3FFE /* Maximum number of bytes in a row of pixels */°dONLNd˘+<6™*OSErr CreateOffScreen(°dONLNd5<@Ü*
  8254. B    Rect       *bounds,     /* Bounding rectangle of off-screen */°dONLNdS?<JÃ*
  8255. P    short      depth,       /* Desired number of bits per pixel in off-screen */°dONLNd§I<Tï*
  8256. E    CTabHandle colors,      /* Color table to assign to off-screen */°dONLNdÍS<^§*
  8257. H    CGrafPtr   *retPort,    /* Returns a pointer to the new CGrafPort */°dONLNd3]<hï*
  8258. E    GDHandle   *retGDevice) /* Returns a handle to the new GDevice */°dONLNdyg<rA*
  8259. {°dONLNd{q<|≥*
  8260. K    CGrafPtr     newPort;     /* Pointer to the new off-screen CGrafPort */°dONLNd«{<Üü*
  8261. G    PixMapHandle newPixMap;   /* Handle to the new off-screen PixMap */°dONLNdÖ<ê§*
  8262. H    GDHandle     newDevice;   /* Handle to the new off-screen GDevice */ ¡X¡
  8263. **2QD 13 - Principia Off-Screen Graphics Environments(÷ˇ9) of 51(ÏZM.QD.PrincipiaOffScreenˇ∂◊#ˇ ˇˇˇˇ#◊ 
  8264. IR,Times
  8265. .+6-Macintosh Technical Notes /4/˘,
  8266. Courier
  8267.     °dONLNd(Ö*I    long         qdVersion;   /* Version of QuickDraw currently in use */°dONLNdJ'2ô*
  8268. M    GrafPtr      savedPort;   /* Pointer to GrafPort used for save/restore */°dONLNdò1<q*
  8269. E    SignedByte   savedState;  /* Saved state of color table handle */°dONLNdfi;FÖ*
  8270. I    short        bytesPerRow; /* Number of bytes per row in the PixMap */°dONLNd(EP&*
  8271. 6    OSErr        error;       /* Returns error code */°dONLNd_Yd
  8272. *1    /* Initialize a few things before we begin */°dONLNdëcnr*
  8273.     newPort = nil;°dONLNd§mx|*
  8274.     newPixMap = nil;°dONLNdπwÇ|*
  8275.     newDevice = nil;°dONLNdŒÅår*
  8276.     error = noErr;°dONLNd·ï†£*O    /* Save the color table’s current state and make sure it isn’t purgeable */°dONLNd1ü™Ü*
  8277.     if (colors != nil)°dONLNdH©¥1*
  8278.     {°dONLNdN≥æ
  8279. *
  8280. 1        savedState = HGetState( (Handle)colors );°dONLNdÄΩ»«*
  8281. #        HNoPurge( (Handle)colors );°dONLNd§«“1*
  8282.     }°dONLNd™€ÊÄ*H    /* Calculate the number of bytes per row in the off-screen PixMap */°dONLNdÛÂî*
  8283. L    bytesPerRow = ((depth * (bounds->right - bounds->left) + 31) >> 5) << 2;°dONLNd@˘Ô*+    /* Get the current QuickDraw version */°dONLNdl5*
  8284. 9    (void)Gestalt( gestaltQuickdrawVersion, &qdVersion );°dONLNd¶"£*O    /* Make sure depth is indexed or depth is direct and 32-Bit QD installed */°dONLNdˆ!,S*
  8285. ?    if (depth == 1 || depth == 2 || depth == 4 || depth == 8 ||°dONLNd6+6ä*
  8286. J            ((depth == 16 || depth == 32) && qdVersion >= gestalt32BitQD))°dONLNdÅ5@1*
  8287.     {°dONLNdá?J£*
  8288. O        /* Maximum number of bytes per row is 16,382; make sure within range */°dONLNd◊IT‡*
  8289. (        if (bytesPerRow <= kMaxRowBytes)°dONLNdS^E*
  8290.             {°dONLNd
  8291. ]hô*
  8292. M            /* Make sure a color table is provided if the depth is indexed */°dONLNdXgrü*
  8293.             if (depth <= 8)°dONLNdtq|T*
  8294.             °dONLNdÅq`|∫)Hif (colors == nil)°dONLNdî{ÜÖ(¢6I                  /* Indexed depth and clut is NIL; is parameter error */°dONLNdfiÖê«*
  8295. #                  error = paramErr;°dONLNdèöE*
  8296.             }°dONLNd ô§T*
  8297.         else°dONLNd£Æî*
  8298. L            /* # of bytes per row is more than 16,382; is parameter error */°dONLNdf≠∏©*
  8299.             error = paramErr;°dONLNdÑ∑¬1*
  8300.     }°dONLNdä¡Ã@*
  8301.     else°dONLNdìÀ÷5*
  8302. 9        /* Pixel depth isn’t valid; is parameter error */°dONLNdÕ’‡ï*
  8303.         error = paramErr;°dONLNdÁÈÙ]*A    /* If sanity checks succeed, then allocate a new CGrafPort */°dONLNd)Û˛ã*
  8304.     if (error == noErr)°dONLNdA˝1*
  8305.     {°dONLNdG5*
  8306. 9        newPort = (CGrafPtr)NewPtr( sizeof (CGrafPort) );°dONLNdÅü*
  8307.         if (newPort != nil)°dONLNdù&E*
  8308.             {°dONLNdß%0€*
  8309. '            /* Save the current port */°dONLNdœ/:¬*
  8310. "            GetPort( &savedPort );°dONLNdÚCNè*K            /* Initialize the new CGrafPort and make it the current port */°dONLNd>MXΩ*
  8311. !            OpenCPort( newPort );°dONLNd`alî*L            /* Set portRect, visRgn, and clipRgn to the given bounds rect */°dONLNd≠kv‡*
  8312. (            newPort->portRect = *bounds;°dONLNd÷uÄ*
  8313. /            RectRgn( newPort->visRgn, bounds );°dONLNd    ä≥*
  8314.             ClipRect( bounds ); ¡4¡˘
  8315. *010)
  8316.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇv◊#ˇ ˇˇˇˇ#◊ 
  8317. IR,Times
  8318. .+Z-Developer Support Center(-Ï
  8319. March 1992 /X/,
  8320. Courier
  8321.     °dONLNd<(Ü(DZB            /* Initialize the new PixMap for off-screen drawing */°dONLNdC'<2ê*
  8322. D            error = SetUpPixMap( depth, bounds, colors, bytesPerRow,°dONLNdà1<<*
  8323. *                    newPort->portPixMap );°dONLNd≥;<F◊*
  8324.             if (error == noErr)°dONLNd”E<P}*
  8325.  
  8326.             {°dONLNd·O<ZT*
  8327. 8                /* Grab the initialized PixMap handle */°dONLNdY<d,*
  8328. 0                newPixMap = newPort->portPixMap;°dONLNdKm<xc*;                /* Allocate and initialize a new GDevice */°dONLNdáw<Çw*
  8329. ?                error = CreateGDevice( newPixMap, &newDevice );°dONLNd«Å<å}*
  8330.  
  8331.             }°dONLNd’ï<†*(            /* Restore the saved port */°dONLNd˛ü<™·*
  8332. !            SetPort( savedPort );°dONLNd ©<¥i*
  8333.             }°dONLNd*≥<æx*
  8334.         else°dONLNd7Ω<»◊*
  8335.             error = MemError();°dONLNdW«<“U*
  8336.     }°dONLNd]€<Ê@*4    /* Restore the given state of the color table */°dONLNdíÂ<™*
  8337.     if (colors != nil)°dONLNd©Ô<˙,*
  8338. 0        HSetState( (Handle)colors, savedState );°dONLNd⁄<J*6    /* One Last Look Around The House Before We Go… */°dONLNd
  8339. <Ø*
  8340.     if (error != noErr)°dONLNd)<"U*
  8341.     {°dONLNd/!<,ï*
  8342. E        /* Some error occurred; dispose of everything we allocated */°dONLNdu+<6Õ*
  8343.         if (newPixMap != nil)°dONLNdì5<@i*
  8344.             {°dONLNdù?<J6*
  8345. 2            DisposCTable( (**newPixMap).pmTable );°dONLNd–I<T,*
  8346. 0            DisposPtr( (**newPixMap).baseAddr );°dONLNdS<^i*
  8347.             }°dONLNd ]<hÕ*
  8348.         if (newDevice != nil)°dONLNd)g<ri*
  8349.             {°dONLNd3q<|c*
  8350. ;            DisposHandle( (Handle)(**newDevice).gdITable );°dONLNdo{<Ü"*
  8351. .            DisposHandle( (Handle)newDevice );°dONLNdûÖ<êi*
  8352.             }°dONLNd®è<ö√*
  8353.         if (newPort != nil)°dONLNdƒô<§i*
  8354.             {°dONLNdŒ£<ÆÊ*
  8355. "            CloseCPort( newPort );°dONLNdÒ≠<∏˙*
  8356. &            DisposPtr( (Ptr)newPort );°dONLNd∑<¬i*
  8357.             }°dONLNd"¡<ÃU*
  8358.     }°dONLNd(À<÷d*
  8359.     else°dONLNd1’<‡U*
  8360.     {°dONLNd7fl<ͬ*
  8361. N        /* Everything’s OK; return refs to off-screen CGrafPort and GDevice */°dONLNdÜÈ<Ù√*
  8362.         *retPort = newPort;°dONLNd¢Û<˛‹*
  8363.          *retGDevice = newDevice;°dONLNd√˝<U*
  8364.     }°dONLNd…<ë*
  8365.     return error;°dONLNd€<A*
  8366. }
  8367. °dONLNd›'<3;*5CreateOffScreen begins by making sure that the color °dONLNd';3˛)ˇ*table, if there is one, doesn’t get purged°dONLNd=3<?û([Zduring the time that °dONLNdR3û?˛)bGthe off-screen graphics environment is created. Then, a sanity check is°dONLNdö?<K‡(gZ"done for the given depth, bounds, °dONLNdº?‡K˛)§<and color table. The depth must be either 1, 2, 4, or 8 bits°dONLNd˘K<Wn(sZ per pixel, °dONLNdKnW˛)2Ror additionally 16 or 32 bits per pixel if 32-Bit QuickDraw is available. If these°dONLNdWW<cç(ZHconditions aren’t satisfied, then it’s decided that there’s an error in °dONLNdüWçc˛(´the parameter list, and°dONLNd∑c<oπ(ãZICreateOffScreen does nothing more. To determine whether 32-Bit QuickDraw °dONLNdcπo˛(ã◊is available or°dONLNdo<{c(óZ    not, the 
  8368. °dONLNdoc{ì)'_Gestalt
  8369. °dONLNd!oì{ñ)0 °dONLNd"oñ{Ò)routine is used. If 
  8370. °dONLNd6oÒ{!)[_Gestalt
  8371. °dONLNd>o!{˛)00 returns a value that’s equal to or greater than°dONLNdo{<áy(£Z
  8372. the constant 
  8373. °dONLNd|{yáÕ)=gestalt32BitQD
  8374. °dONLNdä{ÕáÇ)T%, then 32-Bit QuickDraw is available °dONLNdØ{Çá˛)µand depths of 16 and 32 ¡X¡
  8375. (÷Z2QD 13 - Principia Off-Screen Graphics Environments(÷˙11)
  8376.  of 51(ÏZM.QD.PrincipiaOffScreenˇ ∏◊#ˇ ˇˇˇˇ#◊ 
  8377. IR,Times
  8378. .+6-Macintosh Technical Notes /4/˘
  8379. °dONLNd)X*bits per pixel °dONLNdX)c)@7are supported. It’s not necessary to determine whether ,
  8380. Courier
  8381. °dONLNdFc)ì(EÅ_Gestalt
  8382. °dONLNdNì)⁄)0 is available or°dONLNd_)5Æ(Q6Qnot because it’s implemented as glue code in the Macintosh Programmer’s Workshop.°dONLNd±AML* A check is °dONLNdºALM⁄)4Pthen done to determine whether the number of bytes in each row of the off-screen°dONLNd
  8383. MY_(u6pixel image is °dONLNdM_Y⁄)GFtoo much for QuickDraw to handle. Color QuickDraw can handle up to and°dONLNdcYeı(Å6+including 16,382 ($3FFE) bytes in each row °dONLNdéYıe⁄)›-of any pixel image. If the required number of°dONLNdºeqí(ç6Mbytes per row exceeds this amount, then CreateOffScreen decides that there’s °dONLNd    eíq⁄(ç∞an error in the°dONLNdq}å(ô6Kparameter list and does nothing more. The minimum number of bytes in a row °dONLNddqå}⁄(ô™that’s enough to°dONLNdu}âΩ(•6[cover the given boundary rectangle at the given pixel depth is calculated with the formula:
  8384. °dONLNd—ï°‘*J  bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;
  8385. °dONLNd¨∏(*8This formula multiplies the number of pixels across the 
  8386. °dONLNdT¨(∏L(‘FPixMap
  8387. °dONLNdZ¨L∏´)$ by the pixel depth °dONLNdn¨´∏⁄)_
  8388. to get the°dONLNdy∏ƒx(‡6number of bits, and °dONLNdç∏xƒ⁄)`Jthen this is divided by eight to get the number of bytes. This division by°dONLNdÿƒ–ü(Ï6Neight looks very strange because the number of bytes per row must be even, so °dONLNd&ƒü–⁄(ÏΩ this formula°dONLNd3–‹¶(¯6Stakes advantage of integer division and multiplication to make the result come out °dONLNdÜ–¶‹⁄(¯ƒ
  8389. even. This°dONLNdë‹Ë5(6;particular formula additionally makes sure that the number °dONLNdË5Ë⁄(S!of bytes per row is a multiple of°dONLNdÓËÙı(6-four. This helps optimize the performance of °dONLNdËıÙ⁄)›,Color QuickDraw operations because it allows°dONLNdHÙ®(6OColor QuickDraw to refer to each row beginning on a long word boundary in memor°dONLNdóÙ®Æ(Δy°dONLNdòÙ≠±).°dONLNdö °(46TThe last sanity check is to make sure that a color table is given as a parameter if °dONLNdÓ °⁄(4ø it’s needed.°dONLNd˚$](@6Indexed-color °dONLNd    ]$⁄)EPgraphics environments need color tables, so if the given pixel depth is eight or°dONLNdZ$0-(L6less °dONLNd_$-0⁄)W(which implies an indexed-color graphics environment) and the given color table is NIL,°dONLNd∑0<(X66then CreateOffScreen decides that there’s an error in °dONLNdÌ0<⁄)˘)the parameter list and does nothing more.°dONLNd<H4(d6If the °dONLNd<4H⁄)Wgiven pixel depth is 16 or 32 (which implies a direct-color graphics environment), then°dONLNdvHTÚ(p6.CreateOffScreen ignores the given color table.°dONLNd•`l*6If all the sanity checks succeed, then the off-screen 
  8390. °dONLNd€`lS(à;    CGrafPort
  8391. °dONLNd‰`Sl—)6 is allocated using a call °dONLNdˇ`—l⁄)~to
  8392. °dONLNdlxB(î6_NewPtr
  8393. °dONLNd    lBx∂)*, and then it’s initialized °dONLNd%l∂x)tand opened as a 
  8394. °dONLNd5lx>)R    CGrafPort
  8395. °dONLNd>l>x⁄)6! by passing the resulting pointer°dONLNd`xÑ$(†6to 
  8396. °dONLNdcx$Ñ`)
  8397. _OpenCPort
  8398. °dONLNdmx`Ñë)<
  8399. . Because 
  8400. °dONLNdwxëÑÕ)1
  8401. _OpenCPort
  8402. °dONLNdÅxÕÑÒ)< makes °dONLNdàxÒÑ)$the new 
  8403. °dONLNdêxÑQ)*    CGrafPort
  8404. °dONLNdôxQÑ⁄)6 the current port, the current°dONLNd∏ÑêŒ(¨6`port is first saved so that it can be restored as the current port when CreateOffScreen is done.°dONLNd    ú®Ç*As mentioned above, °dONLNd    -úÇ®ï)jthe 
  8405. °dONLNd    1úﮟ) _OpenCPort 
  8406. °dONLNd    <úŸ®y)D#doesn’t necessarily initialize the 
  8407. °dONLNd    _úy®©)†portRect
  8408. °dONLNd    gú©®≤)0, 
  8409. °dONLNd    iú≤®÷)    visRgn
  8410. °dONLNd    oú÷®⁄)$,°dONLNd    q®¥,(–6and 
  8411. °dONLNd    u®,¥V)clipRgn
  8412. °dONLNd    |®V¥í)*  of the new 
  8413. °dONLNd    à®í¥»)<    CGrafPort
  8414. °dONLNd    ë®»¥⁄)6; to the areas that are needed for any particular off-screen°dONLNd    Õ¥¿á(‹6graphics environment. °dONLNd    „¥á¿å)o4So, the given boundary rectangle is assigned to the 
  8415. °dONLNd
  8416. ¥å¿º(‹™portRect
  8417. °dONLNd
  8418. ¥º¿⁄)0 field,
  8419. °dONLNd
  8420. '¿ÃH(Ë6_RectRgn
  8421. °dONLNd
  8422. /¿HÃ≠)0 is called to make the 
  8423. °dONLNd
  8424. F¿≠×)evisRgn
  8425. °dONLNd
  8426. L¿—ø)$
  8427.  equal to °dONLNd
  8428. V¿¸Ã§)+"the given boundary rectangle, and 
  8429. °dONLNd
  8430. x¿§Ã⁄)®    _ClipRect
  8431. °dONLNd
  8432. ÇÃÿn(Ù6is called to set the 
  8433. °dONLNd
  8434. óÃnÿò)VclipRgn
  8435. °dONLNd
  8436. ûÃòÿÉ)*4 so that it’s equal to the given boundary rectangle.°dONLNd
  8437. ”‰-( 6The 
  8438. °dONLNd
  8439. ◊‰-Q)PixMap
  8440. °dONLNd
  8441. ›‰Qq)$ in the 
  8442. °dONLNd
  8443. ‰q≠) 
  8444. portPixMap
  8445. °dONLNd
  8446. Ô‰≠⁄)<A field needs to be initialized for off-screen drawing, and that’s°dONLNd 1¸(64handled by the SetUpPixMap routine that’s described °dONLNd e¸⁄(<$and defined in “Building the PixMap”°dONLNd ä¸0($6later °dONLNd ê¸0ô)in this Note. Similarl°dONLNd ¶¸ôü)iy°dONLNd ߸ûÔ), the off-screen 
  8447. °dONLNd ∏¸Ô)QGDevice
  8448. °dONLNd ø¸⁄)*( must be created and initialized. That’s°dONLNd Ë`(06handled by the °dONLNd ˜`⁄)HLCreateGDevice routine that’s described and defined in “Building the GDevice”°dONLNd D j(<6later in this Note.°dONLNd X,8n*Once these things °dONLNd j,n8ó)V>are done, CreateOffScreen returns a pointer to the off-screen 
  8449. °dONLNd ®,ó8Õ(Tµ    CGrafPort
  8450. °dONLNd ±,Õ8⁄)6 in°dONLNd µ8D)(`6the 
  8451. °dONLNd π8)DS)retPort
  8452. °dONLNd ¿8SDá)*  parameter °dONLNd À8áD)4and a handle to the off-screen 
  8453. °dONLNd Í8DE)îGDevice
  8454. °dONLNd Ò8EDh)* in the 
  8455. °dONLNd ˘8hD§)#
  8456. retGDevice
  8457. °dONLNd
  8458. 8§D⁄)<  parameter.°dONLNd
  8459. DPº(l6ZThe way to use these references is described in “Playing With Blocks”  later in this Note.°dONLNd
  8460. j\hç*Building the PixMap
  8461. °dONLNd
  8462. ~tÄT*
  8463. _OpenCPort
  8464. °dONLNd
  8465. àtTÄÜ)<
  8466.  initializes °dONLNd
  8467. ïtÜÄò)2the 
  8468. °dONLNd
  8469. ôtòÄ‘)
  8470. portPixMap
  8471. °dONLNd
  8472. £t‘Ä)< field of the 
  8473. °dONLNd
  8474. ±tÄG)=    CGrafPort
  8475. °dONLNd
  8476. ∫tGÄ⁄)6! it’s initializing with a copy of°dONLNd
  8477. ‹Äå,(®6the 
  8478. °dONLNd
  8479. ‡Ä,åP)PixMap
  8480. °dONLNd
  8481. ÊÄPå°)$ of the current 
  8482. °dONLNd
  8483. ˆİåÀ)QGDevice
  8484. °dONLNd
  8485. ˝ÄÀå˜)*. When °dONLNdĘå⁄),-the CreateOffScreen routine described earlier ¡4¡˘
  8486. (÷612)
  8487.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇJ◊#ˇ ˇˇˇˇ#◊ 
  8488. IR,Times
  8489. .+Z-Developer Support Center(-Ï
  8490. March 1992 /X/
  8491. °dONLNd<)¶(EZexecutes, the current ,
  8492. Courier
  8493. °dONLNd¶)–)jGDevice
  8494. °dONLNd–)Q)* is unknown. So, all the °dONLNd6Q)ï)Åfields of the 
  8495. °dONLNdDï)π)DPixMap
  8496. °dONLNdJπ)˛)$
  8497.  that the new
  8498. °dONLNdX)<5r(QZ    CGrafPort
  8499. °dONLNda)r5f)65 receives must be initialized so that it can be used °dONLNdñ)f5˛)Ùfor drawing off screen.* What°dONLNd¥5<AÓ(]Z&follows is an overview of each of the 
  8500. °dONLNd⁄5ÓA)≤PixMap
  8501. °dONLNd‡5A^)$ fields and how °dONLNd5^A˙)L"they should be initialized for off°dONLNd5˙A˛)ú-°dONLNdA<Mà(iZscreen drawing.
  8502. °dONLNd#Y<el*baseAddr
  8503. °dONLNd,Y®e‹)l pointer to °dONLNd7Y‹e˛)49the off-screen pixel image. The off-screen pixel image is°dONLNdqe®qá(çΔ1allocated as a nonrelocatable block in the heap. °dONLNd¢eáq˛)flThe size of this block of°dONLNdºq®}Á(ôΔ
  8504. memory is °dONLNdΔqÁ}U)?calculated from the 
  8505. °dONLNd⁄qU}Ö)nrowBytes
  8506. °dONLNd‚qÖ}˛)0 field, described next,°dONLNd˙}®â·(•ΔAmultiplied by the number of rows in the given boundary rectangle.
  8507. °dONLNd<ï<°l(ΩZrowBytes
  8508. °dONLNdEï®°j)l)number of bytes in each row of the pixel °dONLNdnïj°˛)¬image. This value is calculated°dONLNdé°®≠˚(…Δfrom the formula °dONLNdü°˚≠˛)S5that’s given in the CreateOffScreen routine. The most°dONLNd’≠®πfi(’ΔDsignificant bit of this field should be set so that Color QuickDraw °dONLNd≠fiπ˛(’¸knows°dONLNdπ®≈Ô(·Δthat this is a 
  8509. °dONLNd.πÔ≈)GPixMap
  8510. °dONLNd4π≈c)$ rather than a 
  8511. °dONLNdCπc≈á)PBitMap
  8512. °dONLNdIπá≈˛)$. The maximum value,°dONLNd^≈®—v(ÌΔ-ignoring the most significant bit, is 16,382.
  8513. °dONLNdå›<È`(Zbounds
  8514. °dONLNd웮ȇ)l defines the °dONLNdü›‡È˛)88coordinate system and the dimensions of the pixel image.°dONLNdÿÈ®ı÷(Δ    For most °dONLNd·È÷ı˛).>off-screen drawing, this should be a rectangle that covers the°dONLNd ı®b(Δ'entire off-screen graphics environment.
  8515. °dONLNdH
  8516. <r(5Z    pmVersion
  8517. °dONLNdR
  8518. ®Ñ)l0set of internally and externally defined flags. °dONLNdÇ
  8519. Ñ˛)‹As of 32-Bit QuickDraw°dONLNdô®%Ù(AΔ1.2, only the 
  8520. °dONLNdßÙ%0)L
  8521. baseAddr32
  8522. °dONLNd±0%±)< flag is defined externall°dONLNdÀ±%∑)Åy°dONLNdÃ∂%ˆ) . This flag °dONLNdÿˆ%˛)@is°dONLNd€%®1Ê(MΔ
  8523. described in °dONLNdË%Ê1˛)>5“Choosing Your Off-Screen Memory” later in this Note.°dONLNd1®=¢(YΔ7For most off-screen drawing, this field is set to zero.
  8524. °dONLNdVI<Ul(qZpackType
  8525. °dONLNd_I®Un)l'image compression scheme for pictures. °dONLNdÜInU˛)ΔThe options for this field are°dONLNd•U®a5(}Δdiscussed in the “Graphics °dONLNd¿U5a©)çOverview” chapter of °dONLNd’U©a˛)tInside Macintosh°dONLNdÊa®m¢(âΔ)Volume VI, pages 17-22 through 17-23. In °dONLNda¢m˛)˙this Note, image°dONLNd m®y©(ïΔ9compression isn’t discussed so this field is set to zero.
  8526. °dONLNdZÖ<ël(≠ZpackSize
  8527. °dONLNdcÖ®ëü)l8internally used field. This field is always set to zero.
  8528. °dONLNdúù<©T(≈ZhRes
  8529. °dONLNd°ù®©6)lhorizontal resolution of the °dONLNdæù6©˛)é$pixel map. By default, the QuickDraw°dONLNd„©®µU(—Δ%resolution is 72 dots per inch,which °dONLNd©Uµ˛)≠$is the value this Note uses. This is°dONLNd-µ®¡Ÿ(›ΔDa fixed-point field, so the actual value in this field is $00480000.
  8530. °dONLNdrÕ<ŸT(ıZvRes
  8531. °dONLNdwÕ®Ÿw)l.vertical resolution of the pixel map. See the 
  8532. °dONLNd•ÕwŸè)œhRes
  8533. °dONLNd©Õ蟠)
  8534.  description.
  8535. °dONLNd∑Â<Òr(
  8536. Z    pixelType
  8537. °dONLNd¡®Ò )lformat of the pixels. °dONLNd◊Â Ò˛)c3In indexed-color pixel maps, this field holds zero.°dONLNd Ò®˝(ΔIn direct-color pixel °dONLNd!Ò˝ó)fmaps, this field holds the 
  8538. °dONLNd<Òó˝Õ)â    RGBDirect
  8539. °dONLNdEÒÕ˝˛)6
  8540.  constant,°dONLNdP˝®     (%Δwhich is equal to 16.
  8541. °dONLNdf<!r(=Z    pixelSize
  8542. °dONLNdp®!¸)lnumber of bits in °dONLNdǸ!˛)T7every pixel. For indexed-color pixels, this is 1, 2, 4,°dONLNd∫!®-˝(IΔNor 8 bits per pixel. For direct-color pixels, this is 16 or 32 bits per pixel.
  8543. °dONLNd        9<El(aZcmpCount
  8544. °dONLNd    9®El)l(number of components in every pixel. In °dONLNd    :9lE˛)ƒindexed-color pixel maps, this°dONLNd    YE®Q¡(mΔ:field is set to 1. In direct-color pixel maps, this field °dONLNd    ìE¡Q˛(mfl is set to 3.°dONLNd    †Q®]‡(yΔ
  8545. Sometimes °dONLNd    ™Q‡]˛)8;it’s handy to set this field to 4 in 32-bit deep pixel maps°dONLNd    Ê]®iÌ(ÖΔ
  8546. when they’re °dONLNd    Û]Ìi˛)E3being saved in a picture. See the “Color QuickDraw”°dONLNd
  8547. 'i®u‹(ëΔ chapter of °dONLNd
  8548. 2i‹u2)4Inside Macintosh °dONLNd
  8549. Ci2uâ)VVolume VI, page °dONLNd
  8550. Siâu˛)W17-23, for details about°dONLNd
  8551. lu®ÅΩ(ùΔthis. ¡X¡
  8552. (÷Z2QD 13 - Principia Off-Screen Graphics Environments(÷˙13)
  8553.  of 51(ÏZM.QD.PrincipiaOffScreenˇ¢◊#ˇ ˇˇˇˇ#◊ 
  8554. IR,Times
  8555. .+6-Macintosh Technical Notes /4/˘,
  8556. Courier°dONLNd)B*cmpSize
  8557. °dONLNdÑ)[)l+number of bits in each color component. In °dONLNd3[)⁄)◊indexed-color pixel maps,°dONLNdM)Ñ5Y(Q¢2this field is set to the same value that’s in the 
  8558. °dONLNd)Y5è)’    pixelSize
  8559. °dONLNdà)è5⁄)6 field. In 16-bit°dONLNdö5ÑAù(]¢deep °dONLNdü5ùA⁄)Fdirect pixel maps, this field is set to 5. In 32-bit deep direct pixel°dONLNdÊAÑM(i¢maps, this field is set to 8.
  8560. °dONLNdYeT(Å6
  8561. planeBytes
  8562. °dONLNdYÑe\)l1not currently defined. This field is set to zero.
  8563. °dONLNdAq}B(ô6pmTable
  8564. °dONLNdIqÑ}Z)l,handle to the color table for indexed-color °dONLNduqZ}⁄)÷pixel maps. A method to°dONLNdç}Ñâ7(•¢(create a color table is given in “About °dONLNdµ}7â⁄)≥#That Creation Thing . . .” later in°dONLNdŸâÑï(±¢!this Note. In direct-color pixel °dONLNd˙âï⁄)ó'maps, this field contains a handle to a°dONLNd"ïѰŒ(Ω¢ dummy color °dONLNd.⁄)J0table, and building one of these is shown in the°dONLNd_°Ñ≠((…¢!SetUpPixMap routine in Listing 2.
  8565. °dONLNdÅπ≈T(·6
  8566. pmReserved
  8567. °dONLNdåπÑ≈\)l1not currently defined. This field is set to zero.°dONLNdæ–‹"(¯6(*°dONLNd¿”"fl>+
  8568. ?This part of these routines really bothers me because it feels °dONLNdˇ”>flº(˚\impure to initialize all the 
  8569.     °dONLNd‘ºfl⁄)~PixMap
  8570. °dONLNd#flÎR(6 fields when 
  8571.     °dONLNd/‡RÎÑ):
  8572. _OpenCPort
  8573. °dONLNd9flÑÎ)2 has initialized them alread°dONLNdUflÎ
  8574. )Äy°dONLNdVfl    Î÷)+, just not in a way that’s any good for off°dONLNdÅfl÷Î⁄)Õ-°dONLNdÇΘø(6%screen drawing. I tried creating the 
  8575.     °dONLNdßÏø˜‚)ßGDevice
  8576. °dONLNdÆÎ‚˜˘)# and 
  8577.     °dONLNd≥Ï˘˜)PixMap
  8578. °dONLNdπΘ}) first and then calling 
  8579.     °dONLNd—Ï}˜Ø)f
  8580. _OpenCPort
  8581. °dONLNd€Îؘ‘)2     so that °dONLNd‰Î‘˜⁄)%it°dONLNdÁ˜U(6initializes its 
  8582.     °dONLNd˜¯Us)=PixMap
  8583. °dONLNd˝˜s˙) for off-screen drawing, but °dONLNd˜˙⁄)á,then you end up with two pixel maps and that°dONLNdG8(,6=makes this tougher to explain, or you have to dispose of one °dONLNdÑ8b(,VPixMap°dONLNdäb•)*
  8584.  which seems °dONLNdó•⁄)C
  8585. worse than°dONLNd¢Ö(86the method I’m using.)°dONLNdπ(4*5The SetUpPixMap routine in Listing 2 initializes the 
  8586. °dONLNdÓ(44)¯PixMap
  8587. °dONLNdÙ(44∞)$ that’s passed to it in the 
  8588. °dONLNd(∞4⁄)|aPixMap
  8589. °dONLNd4@t(\6Hparameter so that it can be used in an off-screen graphics environment. °dONLNd`4t@ã(\íThe 
  8590. °dONLNdd4ã@©)depth
  8591. °dONLNdi4©@≤), 
  8592. °dONLNdk4≤@÷)    bounds
  8593. °dONLNdq4÷@⁄)$,°dONLNds@L-(h6and 
  8594. °dONLNdw@-LK)color
  8595. °dONLNd|@KLò) parameters are °dONLNdå@òL⁄)M?the same as the ones passed to the CreateOffScreen routine. The
  8596. °dONLNdÃLXZ(t6 bytesPerRow
  8597. °dONLNd◊LZX≠)BF parameter is the number of bytes in each row of the off-screen pixel °dONLNdL≠X⁄(tÀimage. A°dONLNd&Xd˚(Ä6/description of SetUpPixMap follows the listing.°dONLNdVp|ñ*MPW Pascal Listing 2
  8598.     °dONLNdkàìÅ*FUNCTION SetUpPixMap(°dONLNdÅíùÖ*
  8599. I   depth:       Integer;     {Desired number of bits/pixel in off-screen}°dONLNdÀúßS*
  8600. ?   bound:       Rect;        {Bounding rectangle of off-screen}°dONLNd ¶±b*
  8601. B   colors:      CTabHandle;  {Color table to assign to off-screen}°dONLNdN∞ªl*
  8602. D   bytesPerRow: Integer;     {Number of bytes in each row of pixels}°dONLNdì∫≈q*
  8603. E   aPixMap:     PixMapHandle {Handle to the PixMap being initialized}°dONLNdŸƒœT*
  8604.    ): OSErr;°dONLNdÊÿ„@*   CONST°dONLNdÔ‚ÌÖ*
  8605. I      kDefaultRes = $00480000; {Default resolution is 72 DPI; Fixed type}°dONLNd9ˆ6*   VAR°dONLNd@ è*
  8606. K      newColors:   CTabHandle; {Color table used for the off-screen PixMap}°dONLNdå
  8607. v*
  8608. F      offBaseAddr: Ptr;        {Pointer to the off-screen pixel image}°dONLNd”*
  8609. 3      error:       OSErr;      {Returns error code}°dONLNd    (31*BEGIN°dONLNd    
  8610. 2=r*
  8611.    error := noErr;°dONLNd     <G|*
  8612.    newColors := NIL;°dONLNd    5FQã*
  8613.     offBaseAddr := NIL;°dONLNd    MZe£*O   (* Clone the clut if indexed color; allocate a dummy clut if direct color *)°dONLNd    ùdoÅ*
  8614.    IF depth <= 8 THEN°dONLNd    ≥nyO*
  8615.       BEGIN°dONLNd    øxÉ©*
  8616.          newColors := colors;°dONLNd    ›Çç*
  8617. 0         error := HandToHand(Handle(newColors));°dONLNd
  8618. åóE*
  8619.           END ¡4¡˘
  8620. *#14)
  8621.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇÙ◊#ˇ ˇˇˇˇ#◊ 
  8622. IR,Times
  8623. .+Z-Developer Support Center(-Ï
  8624. March 1992 /X/,
  8625. Courier
  8626.     °dONLNd<(_(DZ   ELSE°dONLNd'<2s*
  8627.       BEGIN°dONLNd1<<w*
  8628. ?         newColors := CTabHandle(NewHandle(SizeOf(ColorTable) -°dONLNdT;<F*
  8629. $               SizeOf(CSpecArray)));°dONLNdyE<P√*
  8630.          error := MemError;°dONLNdïO<Zn*
  8631.  
  8632.       END;°dONLNd†Y<d¥*
  8633.    IF error = noErr THEN°dONLNdπc<ns*
  8634.       BEGIN°dONLNd≈m<xÃ*
  8635. P         (* Allocate pixel image; long integer multiplication avoids overflow *)°dONLNdw<Çï*
  8636. E         offBaseAddr := NewPtr(LongInt(bytesPerRow) * (bound.bottom -°dONLNd\Å<å√*
  8637.                bound.top));°dONLNdxã<ñÎ*
  8638. #         IF offBaseAddr <> NIL THEN°dONLNdúï<†Õ*
  8639.             WITH aPixMap^^ DO°dONLNd∫ü<™†*
  8640.                BEGIN°dONLNdœ©<¥¬*
  8641. N                  (* Initialize fields common to indexed and direct PixMaps *)°dONLNd≥<æw*
  8642. ?                  baseAddr := offBaseAddr;     {Point to image}°dONLNd^Ω<»ã*
  8643. C                  rowBytes := BOR(bytesPerRow, {MSB set for PixMap}°dONLNd¢«<“◊*
  8644.                         $8000);°dONLNd¬—<‹Å*
  8645. A                  bounds := bound;             {Use given bounds}°dONLNd€<ÊÅ*
  8646. A                  pmVersion := 0;              {No special stuff}°dONLNdFÂ<Ü*
  8647. B                  packType := 0;               {Default PICT pack}°dONLNdâÔ<˙≥*
  8648. K                  packSize := 0;               {Always zero when in memory}°dONLNd’˘<Æ*
  8649. J                  hRes := kDefaultRes;         {72 DPI default resolution}°dONLNd <Æ*
  8650. J                  vRes := kDefaultRes;         {72 DPI default resolution}°dONLNdk
  8651. <©*
  8652. I                  pixelSize := depth;          {Set number of bits/pixel}°dONLNdµ<"Y*
  8653. 9                  planeBytes := 0;             {Not used}°dONLNdÔ!<,Y*
  8654. 9                  pmReserved := 0;             {Not used}°dONLNd)5<@Ã*P                  (* Initialize fields specific to indexed and direct PixMaps *)°dONLNdz?<J*
  8655. $                  IF depth <= 8 THEN°dONLNdüI<Tæ*
  8656.                      BEGIN°dONLNd∫S<^'*
  8657. /                        (* PixMap is indexed *)°dONLNdÍ]<hÅ*
  8658. A                        pixelType := 0;       {Indicates indexed}°dONLNd,g<r|*
  8659. @                        cmpCount := 1;        {Have 1 component}°dONLNdmq<|ê*
  8660. D                        cmpSize := depth;     {Component size=depth}°dONLNd≤{<Ür*
  8661. >                        pmTable := newColors; {Handle to CLUT}°dONLNdÒÖ<ê¥*
  8662.                      END°dONLNd
  8663. è<ö™*
  8664.                   ELSE°dONLNd!ô<§æ*
  8665.                      BEGIN°dONLNd<£<Æ"*
  8666. .                        (* PixMap is direct *)°dONLNdk≠<∏Ü*
  8667. B                        pixelType := RGBDirect; {Indicates direct}°dONLNdÆ∑<¬ã*
  8668. C                        cmpCount := 3;          {Have 3 components}°dONLNdÚ¡<Ã*
  8669. *                        IF depth = 16 THEN°dONLNdÀ<÷Ü*
  8670. B                           cmpSize := 5         {5 bits/component}°dONLNd`’<‡»*
  8671.                         ELSE°dONLNd}fl<ÍÜ*
  8672. B                           cmpSize := 8;        {8 bits/component}°dONLNd¿Û<˛§*H                        (* Initialize fields of the dummy color table *)°dONLNd        ˝<ê*
  8673. D                        newColors^^.ctSeed := 3 * aPixMap^^.cmpSize;°dONLNd    N<1*
  8674. 1                        newColors^^.ctFlags := 0;°dONLNd    Ä<,*
  8675. 0                        newColors^^.ctSize := 0;°dONLNd    ±<&*
  8676. -                        pmTable := newColors;°dONLNd    fl%<0π*
  8677.                      END;°dONLNd    ˘/<:ñ*
  8678.                END°dONLNd
  8679. 9<D}*
  8680.  
  8681.          ELSE°dONLNd
  8682. C<N“*
  8683.             error := MemError;°dONLNd
  8684. 9M<Xi*
  8685.           END°dONLNd
  8686. CW<b_*
  8687.    ELSE°dONLNd
  8688. Ka<lØ*
  8689.       newColors := NIL;°dONLNd
  8690. cu<Ä∏*L   (* If no errors occurred, return a handle to the new off-screen PixMap *)°dONLNd
  8691. ∞<äπ*
  8692.    IF error <> noErr THEN°dONLNd
  8693.  â<îs*
  8694.       BEGIN ¡X¡
  8695. *&2QD 13 - Principia Off-Screen Graphics Environments(÷˙15)
  8696.  of 51(ÏZM.QD.PrincipiaOffScreenˇ¬◊#ˇ ˇˇˇˇ#◊ 
  8697. IR,Times
  8698. .+6-Macintosh Technical Notes /4/˘,
  8699. Courier
  8700.     °dONLNd(Ω*!         IF newColors <> NIL THEN°dONLNd"'2Ã*
  8701. $            DisposCTable(newColors);°dONLNdG1<J*
  8702.  
  8703.       END;°dONLNdREP≥*    (* Return the error code *)°dONLNdrOZï*
  8704.     SetUpPixMap := error;°dONLNdåYd,*
  8705. END;
  8706. °dONLNdëo{{*MPW C Listing 2
  8707.     °dONLNd°áíô*M#define kDefaultRes 0x00480000 /* Default resolution is 72 DPI; Fixed type */°dONLNdÔõ¶r*OSErr SetUpPixMap(°dONLNd•∞û*
  8708. N    short        depth,       /* Desired number of bits/pixel in off-screen */°dONLNdQØ∫l*
  8709. D    Rect         *bounds,     /* Bounding rectangle of off-screen */°dONLNdñπƒ{*
  8710. G    CTabHandle   colors,      /* Color table to assign to off-screen */°dONLNdfi√ŒÖ*
  8711. I    short        bytesPerRow, /* Number of bytes per row in the PixMap */°dONLNd(Õÿä*
  8712. J    PixMapHandle aPixMap)     /* Handle to the PixMap being initialized */°dONLNds◊‚*
  8713. {°dONLNdu·Ïî*
  8714. L    CTabHandle newColors;   /* Color table used for the off-screen PixMap */°dONLNd¬Îˆ{*
  8715. G    Ptr        offBaseAddr; /* Pointer to the off-screen pixel image */°dONLNd
  8716. ı*
  8717. 4    OSErr      error;       /* Returns error code */°dONLNd?    r*    error = noErr;°dONLNdR|*
  8718.     newColors = nil;°dONLNdg(Ü*
  8719.     offBaseAddr = nil;°dONLNd~1<®*P    /* Clone the clut if indexed color; allocate a dummy clut if direct color */°dONLNdœ;Fw*
  8720.     if (depth <= 8)°dONLNd„EP1*
  8721.     {°dONLNdÈOZü*
  8722.         newColors = colors;°dONLNdYd*
  8723. 3        error = HandToHand( (Handle *)&newColors );°dONLNd9cn1*
  8724.     }°dONLNd?mx@*
  8725.     else°dONLNdHwÇ1*
  8726.     {°dONLNdNÅåX*
  8727. @        newColors = (CTabHandle)NewHandle( sizeof (ColorTable) -°dONLNdèãñ÷*
  8728. &                sizeof (CSpecArray) );°dONLNd∂ï†ü*
  8729.         error = MemError();°dONLNd“ü™1*
  8730.     }°dONLNdÿ©¥ã*
  8731.     if (error == noErr)°dONLNd≥æ1*
  8732.     {°dONLNdˆΩ»£*
  8733. O        /* Allocate pixel image; long integer multiplication avoids overflow */°dONLNdF«“î*
  8734. L        offBaseAddr = NewPtr( (unsigned long)bytesPerRow * (bounds->bottom -°dONLNdì—‹≥*
  8735.                 bounds->top) );°dONLNd≥€Ê≥*
  8736.         if (offBaseAddr != nil)°dONLNd”ÂE*
  8737.             {°dONLNd›Ô˙Ä*
  8738. H            /* Initialize fields common to indexed and direct PixMaps */°dONLNd&˘q*
  8739. E            (**aPixMap).baseAddr = offBaseAddr;  /* Point to image */°dONLNdlÖ*
  8740. I            (**aPixMap).rowBytes = bytesPerRow | /* MSB set for PixMap */°dONLNd∂
  8741. ü*
  8742.                     0x8000;°dONLNd“"{*
  8743. G            (**aPixMap).bounds = *bounds;        /* Use given bounds */°dONLNd!,{*
  8744. G            (**aPixMap).pmVersion = 0;           /* No special stuff */°dONLNdb+6Ä*
  8745. H            (**aPixMap).packType = 0;            /* Default PICT pack */°dONLNd´5@Ö*
  8746. I            (**aPixMap).packSize = 0;            /* Always zero in mem */°dONLNdı?JÖ*
  8747. I            (**aPixMap).hRes = kDefaultRes;      /* 72 DPI default res */°dONLNd?ITÖ*
  8748. I            (**aPixMap).vRes = kDefaultRes;      /* 72 DPI default res */°dONLNdâS^{*
  8749. G            (**aPixMap).pixelSize = depth;       /* Set # bits/pixel */°dONLNd—]hS*
  8750. ?            (**aPixMap).planeBytes = 0;          /* Not used */°dONLNd    grS*
  8751. ?            (**aPixMap).pmReserved = 0;          /* Not used */ ¡4¡˘
  8752. *H16)
  8753.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇr◊#ˇ ˇˇˇˇ#◊ 
  8754. IR,Times
  8755. .+Z-Developer Support Center(-Ï
  8756. March 1992 /X/,
  8757. Courier
  8758.     °dONLNd<(Æ(DZJ            /* Initialize fields specific to indexed and direct PixMaps */°dONLNdK'<2√*
  8759.             if (depth <= 8)°dONLNdg1<<}*
  8760.  
  8761.             {°dONLNdu;<Fˇ*
  8762. '                /* PixMap is indexed */°dONLNdùE<P§*
  8763. H                (**aPixMap).pixelType = 0;       /* Indicates indexed */°dONLNdÊO<Zü*
  8764. G                (**aPixMap).cmpCount = 1;        /* Have 1 component */°dONLNd.Y<d≥*
  8765. K                (**aPixMap).cmpSize = depth;     /* Component size=depth */°dONLNdzc<nï*
  8766. E                (**aPixMap).pmTable = newColors; /* Handle to CLUT */°dONLNd¿m<x}*
  8767.  
  8768.             }°dONLNdŒw<Çå*
  8769.             else°dONLNdflÅ<å}*
  8770.  
  8771.             {°dONLNdÌã<ñ˙*
  8772. &                /* PixMap is direct */°dONLNdï<†©*
  8773. I                (**aPixMap).pixelType = RGBDirect; /* Indicates direct */°dONLNd^ü<™Æ*
  8774. J                (**aPixMap).cmpCount = 3;          /* Have 3 components */°dONLNd©©<¥‹*
  8775.                  if (depth == 16)°dONLNd ≥<æ©*
  8776. I                    (**aPixMap).cmpSize = 5;       /* 5 bits/component */°dONLNdΩ<»†*
  8777.                 else°dONLNd)«<“©*
  8778. I                    (**aPixMap).cmpSize = 8;       /* 8 bits/component */°dONLNds—<‹w*
  8779. ?                (**newColors).ctSeed = 3 * (**aPixMap).cmpSize;°dONLNd≥€<Ê*
  8780. *                (**newColors).ctFlags = 0;°dONLNdfiÂ<    *
  8781. )                (**newColors).ctSize = 0;°dONLNdÔ<˙,*
  8782. 0                (**aPixMap).pmTable = newColors;°dONLNd9˘<}*
  8783.  
  8784.             }°dONLNdG<i*
  8785.             }°dONLNdQ
  8786. <x*
  8787.         else°dONLNd^<"◊*
  8788.             error = MemError();°dONLNd~!<,U*
  8789.     }°dONLNdÑ+<6d*
  8790.     else°dONLNdç5<@¥*
  8791.         newColors = nil;°dONLNd¶I<TΩ*M    /* If no errors occurred, return a handle to the new off-screen PixMap */°dONLNdÙS<^Ø*
  8792.     if (error != noErr)°dONLNd ]<hU*
  8793.     {°dONLNdg<rÕ*
  8794.         if (newColors != nil)°dONLNd0q<|˙*
  8795. &            DisposCTable( newColors );°dONLNdW{<ÜU*
  8796.     }°dONLNd]è<ö◊*    /* Return the error code */°dONLNd}ô<§ë*
  8797.     return error;°dONLNdè£<ÆA*
  8798. }
  8799. °dONLNdëπ<≈(*(SetUpPixMap begins by copying the given °dONLNdππ(≈˛)Ï(color table if an indexed-color graphics°dONLNd‚≈<—(ÌZ,environment is being built, or allocating a °dONLNd≈—˛)‹,dummy color table if a direct-color graphics°dONLNd;—<›˜(˘Z&environment is being built. A copy of °dONLNda—˜›˛)ª5the color table is made because this allows the given°dONLNdó›<È·(Zcolor table and the off-screen °dONLNd∂›·È˛)•4graphics environment’s color table to be manipulated°dONLNdÎÈ<ı÷(ZPindependently without interfering with each other, and this lets the off-screen °dONLNd;È÷ı˛(Ùgraphics°dONLNdDı<L(Z8environment routines manipulate the color table without °dONLNd|ıL˛(j"needing to worry about whether the°dONLNdü<
  8800. ∂()ZOcolor table is a 'clut' resource or not. The dummy color table is made so that °dONLNdÓ∂
  8801. ˛()‘routines which°dONLNd˝
  8802. <ß(5ZKassume that every PixMap has a color table won’t do something catastrophic °dONLNdH
  8803. ߲(5≈if they find a NIL°dONLNd[<%x(AZ
  8804. color table. °dONLNdhx%˛)<MThe off-screen pixel image is then allocated as a nonrelocatable block in the°dONLNd∂%<1ï(MZapplication’s heap.°dONLNd =<I∞*Some of the fields of a 
  8805. °dONLNd‚=∞I‘)tPixMap
  8806. °dONLNdË=‘I≈)$3 have to be initialized differently depending upon °dONLNd    =≈I˛)Ò whether the°dONLNd    'I<U™(qZLindexed-color model or the direct-color model is being used. So, the fields °dONLNd    sI™U˛(q»that are the same°dONLNd    ÖU<a(}Z0regardless of the color model that’s being used °dONLNd    µUa˛)fl0are assigned first. Then the desired pixel depth°dONLNd    Êa<mZ(âZ@is compared to 8. If the depth is less than or equal to 8, then °dONLNd
  8807. &aZm˛(âx&the rest of the fields are initialized°dONLNd
  8808. Mm<y(ïZ,for the indexed-color model. Otherwise, the °dONLNd
  8809. ymy˛)“7rest of the fields are initialized for the direct color°dONLNd
  8810. ±y<ÖR(°Z8model. In the case of the direct-color model, the dummy °dONLNd
  8811. ÈyRÖ˛(°p%color table is initialized to have no ¡X¡
  8812. (÷Z2QD 13 - Principia Off-Screen Graphics Environments(÷˙17)
  8813.  of 51(ÏZM.QD.PrincipiaOffScreenˇ:◊#ˇ ˇˇˇˇ#◊ 
  8814. IR,Times
  8815. .+6-Macintosh Technical Notes /4/˘,
  8816. Courier°dONLNd)T*
  8817. CSpecArray
  8818. °dONLNd
  8819. T)õ)< entries and its 
  8820. °dONLNdõ)ø)GctSeed
  8821. °dONLNd!ø))$ field is set to °dONLNd2)⁄)B*three times the component size. This dummy°dONLNd])5æ(Q6'color table is then installed into the 
  8822. °dONLNdÑ)æ5‚)¶PixMap
  8823. °dONLNdä)‚5Ê)$.°dONLNdåAM≤(i6Once SetUpPixMap completes, °dONLNd®A≤M≈)öthe 
  8824. °dONLNd¨A≈MÈ)PixMap
  8825. °dONLNd≤AÈM))$  of the new 
  8826. °dONLNdæA)M_)@    CGrafPort
  8827. °dONLNd«A_M÷)6 is ready to hold an off°dONLNdflA÷M⁄)w-°dONLNd‡MYÛ(u6/screen image. It’s not quite ready to be drawn °dONLNdMÛY⁄)€-into with Color QuickDraw though. To do that,°dONLNd=Ye^(Å6the off-screen 
  8828. °dONLNdLY^eà)FGDevice
  8829. °dONLNdSYàe’)* is still needed; °dONLNdeY’eù)M+the construction and initialization of the 
  8830. °dONLNdêYùe«)»GDevice
  8831. °dONLNdóY«e⁄)* are°dONLNdúeqô(ç6covered in the next section.°dONLNdπ}âí*Building the GDevice°dONLNdŒï°-*The 
  8832. °dONLNd“ï-°i)
  8833. _OpenCPort
  8834. °dONLNd‹ïi°G)<3 routine automatically allocates and initializes a 
  8835. °dONLNdïG°k)fiPixMap
  8836. °dONLNdïk°ó)$
  8837. , and the °dONLNdïó°⁄), SetUpPixMap°dONLNd+°≠∞(…6$routine reinitializes that existing 
  8838. °dONLNdO°∞≠‘)òPixMap
  8839. °dONLNdU°‘≠€)$. 
  8840. °dONLNdW°€≠)
  8841. _OpenCPort
  8842. °dONLNda°≠£)<! doesn’t allocate nor initialize °dONLNdǰ£≠¨)åa 
  8843. °dONLNdѰ¨≠÷)    GDevice
  8844. °dONLNdã°÷≠⁄)*,°dONLNdç≠π&(’6so °dONLNdê≠&π⁄)Vone has to be created from scratch. Pages 21-20 through 21-21 of “The Graphics Devices°dONLNdÁπ≈Å(·6Manager” chapter of °dONLNd˚πÅ≈Ÿ)iInside Macintosh °dONLNd πŸ≈·)XV°dONLNd
  8845. π‡≈R)olume VI describe the 
  8846. °dONLNd#πR≈î)r _NewGDevice
  8847. °dONLNd.πî≈⁄)B routine. This°dONLNd=≈—(Ì65routine seems as though it’s the ticket to getting a 
  8848. °dONLNdr≈—A)ˇGDevice
  8849. °dONLNdy≈A—é)* for off-screen °dONLNdâ≈é—⁄)Mdrawing, but it°dONLNdô—›i(˘6always allocates °dONLNd™—i›ï)Qthe new 
  8850. °dONLNd≤—ï›ø),GDevice
  8851. °dONLNdπ—ø›⁄)*7 in the system heap. That’s not so good because if your°dONLNdÒ›È0(6<program unexpectedly quits or if you just forget to dispose °dONLNd-›0ÈP(Nof the 
  8852. °dONLNd4›PÈz) GDevice
  8853. °dONLNd;›zÈ⁄)* before you quit for°dONLNdPÈıG(6
  8854. real, the 
  8855. °dONLNdZÈGıq)/GDevice
  8856. °dONLNdaÈqıê)* gets °dONLNdgÈêı⁄)<orphaned in the system heap. To prevent this from happening,
  8857. °dONLNd§ıZ(6 _NewGDevice
  8858. °dONLNdØıZ)B& should be ignored and the off-screen 
  8859. °dONLNd’ı>)∫GDevice
  8860. °dONLNd‹ı>ã)* should instead °dONLNdÏıã⁄)Mbe allocated and°dONLNd˝
  8861. Æ()6initialized from scratch. What °dONLNdÆ
  8862. ∞)ñ2follows is a description of how each field of the 
  8863. °dONLNdN∞
  8864. ⁄()ŒGDevice
  8865. °dONLNdV
  8866. ¶(56 structure should be initialized.
  8867. °dONLNdw%1H*gdRefNum
  8868. °dONLNdÄ%Ñ1¥)l
  8869. reference °dONLNdä%¥1⁄)08number of video driver. Off-screen graphics environments°dONLNd√1Ñ=ø(Y¢ don’t need °dONLNdŒ1ø=⁄);5to have video drivers because there’s no video device°dONLNd=ÑIf(e¢3associated with them, so this field is set to zero.
  8870. °dONLNd8Ua0(}6gdID
  8871. °dONLNd=UÑa)lused to identify specific 
  8872. °dONLNdWUa=)èGDevice
  8873. °dONLNd^U=a†)* structures from °dONLNdoU†a⁄)c color-search°dONLNd|aÑmv(â¢0procedures. This isn’t necessary for off-screen °dONLNd¨avm⁄)Údrawing, so this is°dONLNd¿mÑyÂ(ï¢normally set to zero.
  8874. °dONLNd÷Öë<(≠6gdType
  8875. °dONLNd›ÖÑë™)ltype of 
  8876. °dONLNdÂÖ™ë‘)&GDevice
  8877. °dONLNdÏÖ‘ë)*
  8878. . This field °dONLNd˘Öëz):is set to the constant 
  8879. °dONLNdÖzë™)lclutType
  8880. °dONLNdÖ™ë⁄)0
  8881.  (equal to°dONLNd#ëÑù(π¢zero) for an indexed-color °dONLNd>ëù⁄)í#environment and set to the constant
  8882. °dONLNdbùÑ©¿(≈¢
  8883. directType
  8884. °dONLNdlù¿©ç)<- (equal to 2) for a direct-color environment.
  8885. °dONLNdöµ¡H(›6gdITable
  8886. °dONLNd£µÑ¡#)l%handle to the inverse table. Initiall°dONLNd»µ#¡))üy°dONLNd…µ(¡¡)&, this field is set to an arbitrarily °dONLNdÔµ¡¡⁄)ôsmall°dONLNdı¡ÑÕ›(È¢handle. Later, the 
  8887. °dONLNd¡›Õ)Y _MakeITable
  8888. °dONLNd¡ÕT)B  routine is °dONLNd¡TÕ⁄)5used to resize and initialize°dONLNd=ÕÑŸ!(ı¢$this handle to a real inverse table.
  8889. °dONLNdbÂÒN(
  8890. 6    gdResPref
  8891. °dONLNdlÂÑÒ)linverse-table resolution. When 
  8892. °dONLNdãÂÒ])ó _MakeITable
  8893. °dONLNdñÂ]Ò⁄)B is called by QuickDraw,°dONLNdØÒÑ˝æ(¢
  8894. the value of °dONLNdºÒæ˝⁄):>this field is used as the inverse-table resolution. Almost all°dONLNd˚˝Ñ    B(%¢'inverse tables have a resolution of 4. °dONLNd    "˝B    ⁄)æThere are some cases when a°dONLNd    >    Ñ@(1¢)inverse-table resolution of 5 is useful, °dONLNd    g    @⁄)º particularly when the arithmetic°dONLNd    àÑ!˜(=¢transfer modes are used °dONLNd    †˜!)swith 
  8895. °dONLNd    •!F)    _CopyBits
  8896. °dONLNd    ÆF!⁄)6. See “The GDevice” earlier in°dONLNd    Õ!Ñ-≥(I¢
  8897. this Note.
  8898. °dONLNd    ÿ9E`(a6 gdSearchProc
  8899. °dONLNd    Â9ÑEÀ)lpointer to the °dONLNd    Ù9ÀE⁄)G6color-search procedure. If a color-search procedure is°dONLNd
  8900. +EÑQb(m¢3needed, this field can be set later by calling the 
  8901. °dONLNd
  8902. ^EbQû)fi
  8903. _AddSearch
  8904. °dONLNd
  8905. hEûQ⁄)<
  8906.  routine (see°dONLNd
  8907. vQÑ](y¢the “Color Manager” chapter °dONLNd
  8908. íQ])äof °dONLNd
  8909. ïQ]r)Inside Macintosh °dONLNd
  8910. ¶Qr]z)VV°dONLNd
  8911. ßQy]ö)olume °dONLNd
  8912. ≠Qö]¢)!V°dONLNd
  8913. ÆQ°]⁄) , pages 145°dONLNd
  8914. ∫]ÑiË(Ö¢through 147). Usuall°dONLNd
  8915. Œ]ËiÓ)dy°dONLNd
  8916. œ]Ìi∏)1, this field is just set to NIL and left at that. ¡4¡˘
  8917. (÷618)
  8918.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ◊#ˇ ˇˇˇˇ#◊ 
  8919. IR,Times
  8920. .+Z-Developer Support Center(-Ï
  8921. March 1992 /X/,
  8922. Courier°dONLNd<)x(EZ
  8923. gdCompProc
  8924. °dONLNd ®)Q)l pointer to the color-complement °dONLNd+Q)˛)© procedure. If a color-complement°dONLNdL)®5⁄(QΔ
  8925. procedure °dONLNdV)⁄5Œ)26is needed, this field can be set later by calling the 
  8926. °dONLNdå)Œ5˛)Ù_AddComp
  8927. °dONLNdï5®AL(]Δ!routine (see the “Color Manager” °dONLNd∂5LAÇ)§ chapter of °dONLNd¡5ÇA⁄)6Inside Macintosh °dONLNd“5⁄A‚)XV°dONLNd”5·A˛)olume°dONLNdŸA®M∞(iΔV°dONLNd⁄AØM∂), °dONLNd‹A∂MQ)pages 145 through 147). Usuall°dONLNd˙AQMW)õy°dONLNd˚AVM˛)&, this field is set to NIL and left at°dONLNd"M®YΩ(uΔthat.
  8928. °dONLNd(e<qf(çZgdFlags
  8929. °dONLNd0e®q)lflags indicating certain °dONLNdIeqS)mstates of the 
  8930. °dONLNdWeSq})>GDevice
  8931. °dONLNd^e}q˛)*. This field should initially°dONLNd|q®}#(ôΔbe set to zeroes. After the 
  8932. °dONLNdòq#}M){GDevice
  8933. °dONLNdüqM}≥)* has been built, these °dONLNd∂q≥}˛)fflags can be set°dONLNd«}®â›(•Δ    with the 
  8934. °dONLNd–}›â7)5_SetDeviceAttrs
  8935. °dONLNdfl}7âj)Z     routine °dONLNdË}jâ˛)3(see the “Graphics Devices°dONLNdâ®ï (±ΔManager” chapter of °dONLNdâ ï_)cInside Macintosh °dONLNd(â_ïg)TV°dONLNd)âfïÜ)olume °dONLNd/âÜï˙) VI, pages 21-10 and 21°dONLNdEâ˙ï˛)t-°dONLNdFï®°º(ΩΔ22).
  8936. °dONLNdK≠<π`(’ZgdPMap
  8937. °dONLNdR≠®πfi)l handle to a 
  8938. °dONLNd^≠fiπ)6PixMap
  8939. °dONLNdd≠πB)$. A handle to °dONLNdr≠BπT)@the 
  8940. °dONLNdv≠Tπx)PixMap
  8941. °dONLNd|≠xπú)$ of the 
  8942. °dONLNdÑ≠úπ“)$    CGrafPort
  8943. °dONLNdç≠“π˛)6     that was°dONLNdóπ®≈K(·Δ'created earlier is put into this field.
  8944. °dONLNdø—<›l(˘ZgdRefCon
  8945. °dONLNd»—®›
  8946. )lmiscellaneous data. 
  8947. °dONLNd‹—
  8948. ›I)e
  8949. _CalcCMask
  8950. °dONLNdÊ—I›f)< and 
  8951. °dONLNdΗf›¢)
  8952. _SeedCFill
  8953. °dONLNdı—¢›˛)< use this field as°dONLNd›®Èm(Δ$described on pages 71 through 72 of °dONLNd,›mÈê)≈Inside °dONLNd3›êÈ»)#
  8954. Macintosh °dONLNd=›»È–)8V°dONLNd>›œÈÛ)olume °dONLNdD›ÛÈ˚)$V°dONLNdE›˙È˛).°dONLNdGÈ®ıΔ(ΔInitiall°dONLNdOÈΔıÃ)y°dONLNdPÈÀı=), this field is set to zero.
  8955. °dONLNdm<
  8956. l()ZgdNextGD
  8957. °dONLNdv®
  8958. Û)lhandle to next 
  8959. °dONLNdÖÛ
  8960. )KGDevice
  8961. °dONLNdå
  8962. C)* in the 
  8963. °dONLNdîC
  8964. m)&GDevice
  8965. °dONLNdõm
  8966. Δ)* list. The system °dONLNd≠Δ
  8967. ˛)Y maintains a°dONLNdπ
  8968. ®»(5Δlinked °dONLNd¿
  8969. »Ë) list of 
  8970. °dONLNd»
  8971. Ë) GDevice
  8972. °dONLNdœ
  8973. §)* records in which there’s one 
  8974. °dONLNdÌ
  8975. §Œ)íGDevice
  8976. °dONLNdÙ
  8977. Œ˛)*
  8978.  for every°dONLNdˇ®%˛(AΔscreen, and the °dONLNd˛%‘)V)links are kept in this field. Off-screen 
  8979. °dONLNd8‘%˛)÷GDevice
  8980. °dONLNd@%®1±(MΔ=structures should never be put into this list, so this field °dONLNd}%±1˛(Mœshould be set to°dONLNdé1®=¿(YΔNIL.
  8981. °dONLNdìI<U`(qZgdRect
  8982. °dONLNdöI®UË)l
  8983. rectangle of 
  8984. °dONLNdßIËU)@GDevice
  8985. °dONLNdÆIU‘)*(. Strictly speaking, this field is used °dONLNd÷I‘U˛)¬only for°dONLNdflU®a_(}Δ&screens, but it should be the same as °dONLNdU_ar)∑the 
  8986. °dONLNd    Urañ)bounds
  8987. °dONLNdUña˙)$ rectangle of the off°dONLNd$U˙a˛)d-°dONLNd%a®m…(âΔscreen 
  8988. °dONLNd,a…mÌ)!PixMap
  8989. °dONLNd2aÌmÒ)$.
  8990. °dONLNd4y<Ö`(°ZgdMode
  8991. °dONLNd;y®ÖE)l"current video mode. This field is °dONLNd]yEÖ˛)ù&used by video drivers to keep track of°dONLNdÑÖ®ë∫(≠Δthe °dONLNdàÖ∫ë‘)9current mode that the video device is in. For off-screen 
  8992. °dONLNd¡Ö‘ë˛(≠ÚGDevice
  8993. °dONLNd…ë®ùd(πΔ+structures, this field should be set to -1.
  8994. °dONLNdı©<µT(—ZgdCC
  8995. °dONLNd˘©Tµ`)…°dONLNd˚©®µ»)TThese °dONLNd©»µb) four fields are used only with 
  8996. °dONLNd ©bµå)öGDevice
  8997. °dONLNd'©åµ˛)* structures for screens.°dONLNd@µ®¡Ô(›ΔFor off-screen 
  8998. °dONLNdOµÔ¡)GGDevice
  8999. °dONLNdVµ¡Ó)*0 structures, these fields should be set to zero.
  9000. °dONLNdáÕ<Ÿx(ıZ
  9001. gdReserved
  9002. °dONLNdíÕ®ŸÄ)l1not currently defined. This field is set to zero.°dONLNdƒÂ<ÒS(
  9003. ZThe °dONLNd»ÂSÒ‘)KCreateGDevice routine shown below in Listing 3 allocates and initializes a 
  9004. °dONLNdÂ‘Ò˛(
  9005. ÚGDevice
  9006. °dONLNdÒ<˝ (Z/structure. It takes the initialized off-screen 
  9007. °dONLNdJÒ ˝/)œPixMap
  9008. °dONLNdPÒ/˝@)$ in °dONLNdTÒ@˝S)the 
  9009. °dONLNdXÒS˝è)
  9010. basePixMap
  9011. °dONLNdbÒè˝˛)< parameter and returns°dONLNdy˝<    M(%Zthe °dONLNd}˝M    ~) initialized 
  9012. °dONLNdâ˝~    ®)1GDevice
  9013. °dONLNdê˝®    À)* in the 
  9014. °dONLNdò˝À    )#
  9015. retGDevice
  9016. °dONLNd¢˝    ˛)<2 parameter. If any error occurs, any memory that’s°dONLNd’    <ö(1ZNallocated is disposed of and the result code is returned as a function result.°dONLNd$!<-∫*MPW Pascal Listing 3
  9017.     °dONLNd99<DØ*FUNCTION CreateGDevice(°dONLNdQC<NÆ*
  9018. J   basePixMap:     PixMapHandle; {Handle to the PixMap to base GDevice on}°dONLNdúM<Xö*
  9019. F   VAR retGDevice: GDHandle      {Returns a handle to the new GDevice}°dONLNd„W<bx*
  9020.    ): OSErr;°dONLNdk<vd*   CONST°dONLNd˘u<Ä"*
  9021. .      kITabRes = 4; {Inverse-table resolution} ¡X¡
  9022. *:2QD 13 - Principia Off-Screen Graphics Environments(÷˙19)
  9023.  of 51(ÏZM.QD.PrincipiaOffScreenˇR◊#ˇ ˇˇˇˇ#◊ 
  9024. IR,Times
  9025. .+6-Macintosh Technical Notes /4/˘,
  9026. Courier
  9027.     °dONLNd(6*   VAR°dONLNd'25*
  9028. 9      newDevice:  GDHandle;   {Handle to the new GDevice}°dONLNdA1<q*
  9029. E      embryoITab: ITabHandle; {Handle to the embryonic inverse table}°dONLNdá;FÍ*
  9030. *      error:      OSErr;      {Error code}°dONLNd≤OZ1*BEGIN°dONLNd∏Yd*
  9031. 0   (* Initialize a few things before we begin *)°dONLNdÈcnr*
  9032.    error := noErr;°dONLNd¸mx|*
  9033.    newDevice := NIL;°dONLNdwÇÅ*
  9034.    embryoITab := NIL;°dONLNd'ãñÙ*,   (* Allocate memory for the new GDevice *)°dONLNdTï†!*
  9035. 5   newDevice := GDHandle(NewHandle(SizeOf(GDevice)));°dONLNdäü™ü*
  9036.    IF newDevice <> NIL THEN°dONLNd¶©¥O*
  9037.       BEGIN°dONLNd≤≥æ*
  9038. 3         (* Allocate the embryonic inverse table *)°dONLNdÊΩ»!*
  9039. 5         embryoITab := ITabHandle(NewHandleClear(2));°dONLNd«“¬*
  9040. "         IF embryoITab <> NIL THEN°dONLNd?—‹m*
  9041.             BEGIN°dONLNdQ€Ê&*
  9042. 6               (* Initialize the new GDevice fields *)°dONLNdàÂ¬*
  9043. "               WITH newDevice^^ DO°dONLNd´Ô˙ã*
  9044.                   BEGIN°dONLNd√˘è*
  9045. K                     gdRefNum := 0;                 {Only used for screens}°dONLNdÄ*
  9046. H                     gdID := 0;                     {Won’t normally use}°dONLNdX
  9047. 0*
  9048. 8                     IF basePixMap^^.pixelSize <= 8 THEN°dONLNdë"ä*
  9049. J                        gdType := clutType          {Depth≤8; clut device}°dONLNd‹!,ï*
  9050.                      ELSE°dONLNdˆ+6î*
  9051. L                        gdType := directType;       {Depth>8; direct device}°dONLNdC5@è*
  9052. K                     gdITable := embryoITab;        {2-byte handle for now}°dONLNdè?Jä*
  9053. J                     gdResPref := kITabRes;         {Normal inv table res}°dONLNd⁄ITä*
  9054. J                     gdSearchProc := NIL;           {No color-search proc}°dONLNd%S^Ä*
  9055. H                     gdCompProc := NIL;             {No complement proc}°dONLNdn]hä*
  9056. J                     gdFlags := 0;                  {Will set these later}°dONLNdπgrä*
  9057. J                     gdPMap := basePixMap;          {Reference our PixMap}°dONLNdq|Ä*
  9058. H                     gdRefCon := 0;                 {Won’t normally use}°dONLNdM{ÜÖ*
  9059. I                     gdNextGD := NIL;               {Not in GDevice list}°dONLNdóÖêè*
  9060. K                     gdRect := basePixMap^^.bounds; {Use PixMap dimensions}°dONLNd„èöl*
  9061. D                     gdMode := -1;                  {For nonscreens}°dONLNd(ô§è*
  9062. K                     gdCCBytes := 0;                {Only used for screens}°dONLNdt£Æè*
  9063. K                     gdCCDepth := 0;                {Only used for screens}°dONLNd¿≠∏è*
  9064. K                     gdCCXData := NIL;              {Only used for screens}°dONLNd ∑¬è*
  9065. K                     gdCCXMask := NIL;              {Only used for screens}°dONLNdX¡Ãv*
  9066. F                     gdReserved := 0;               {Currently unused}°dONLNdüÀ÷Ü*
  9067.                   END;°dONLNd∂flÍ{*G               (* Set color-device bit if PixMap isn’t black & white *)°dONLNd˛ÈÙ
  9068. *
  9069. 1               IF basePixMap^^.pixelSize > 1 THEN°dONLNd    0Û˛]*
  9070. A                  SetDeviceAttribute(newDevice, gdDevType, true);°dONLNd    rô*M               (* Set bit to indicate that the GDevice has no video driver *)°dONLNd    ¿I*
  9071. =               SetDeviceAttribute(newDevice, noDriver, true);°dONLNd    ˛%0
  9072. *1               (* Initialize the inverse table *)°dONLNd
  9073. 0/:*
  9074. 2               IF basePixMap^^.pixelSize <= 8 THEN°dONLNd
  9075. c9Dã*
  9076.                   BEGIN°dONLNd
  9077. {CNè*
  9078. K                     MakeITable(basePixMap^^.pmTable, newDevice^^.gdITable,°dONLNd
  9079. «MX*
  9080. 2                           newDevice^^.gdResPref);°dONLNd
  9081. ˙Wb÷*
  9082. &                     error := QDError;°dONLNd !alÜ*
  9083.                   END;°dONLNd 8kvc*
  9084.             END°dONLNd HuÄY*
  9085.  
  9086.          ELSE°dONLNd VäÆ*
  9087.             error := MemError;°dONLNd uâîE*
  9088.           END ¡4¡˘
  9089. *&20)
  9090.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ◊#ˇ ˇˇˇˇ#◊ 
  9091. IR,Times
  9092. .+Z-Developer Support Center(-Ï
  9093. March 1992 /X/,
  9094. Courier
  9095.     °dONLNd<(_(DZ   ELSE°dONLNd'<2¥*
  9096.       error := MemError;°dONLNd!;<F*(   (* Handle any errors along the way *)°dONLNdJE<Pπ*
  9097.    IF error <> noErr THEN°dONLNddO<Zs*
  9098.       BEGIN°dONLNdpY<dÊ*
  9099. "         IF embryoITab <> NIL THEN°dONLNdìc<n*
  9100. -            DisposHandle(Handle(embryoITab));°dONLNd¡m<x·*
  9101. !         IF newDevice <> NIL THEN°dONLNd„w<Ç*
  9102. ,            DisposHandle(Handle(newDevice));°dONLNdÅ<åi*
  9103.           END°dONLNdã<ñ_*
  9104.    ELSE°dONLNd"ï<†“*
  9105.       retGDevice := newDevice;°dONLNdA©<¥*+   (* Return a handle to the new GDevice *)°dONLNdm≥<ææ*
  9106.    CreateGDevice := error;°dONLNdàΩ<»P*
  9107. END;
  9108. °dONLNdç”<flü*MPW C Listing 3
  9109.     °dONLNdùÎ<ˆ1*1#define kITabRes 4 /* Inverse-table resolution */°dONLNdœˇ<
  9110. †*OSErr CreateGDevice(°dONLNd‰    <≥*
  9111. K    PixMapHandle basePixMap,  /* Handle to the PixMap to base GDevice on */°dONLNd0<ü*
  9112. G    GDHandle     *retGDevice) /* Returns a handle to the new GDevice */°dONLNdx<(A*
  9113. {°dONLNdz'<2^*
  9114. :    GDHandle   newDevice;  /* Handle to the new GDevice */°dONLNdµ1<<ö*
  9115. F    ITabHandle embryoITab; /* Handle to the embryonic inverse table */°dONLNd¸;<FE*
  9116. 5    Rect       deviceRect; /* Rectangle of GDevice */°dONLNd2E<P*
  9117. +    OSErr      error;      /* Error code */°dONLNd^Y<d1*1    /* Initialize a few things before we begin */°dONLNdêc<nñ*
  9118.     error = noErr;°dONLNd£m<x†*
  9119.     newDevice = nil;°dONLNd∏w<Ç•*
  9120.     embryoITab = nil;°dONLNdŒã<ñ*-    /* Allocate memory for the new GDevice */°dONLNd¸ï<†T*
  9121. 8    newDevice = (GDHandle)NewHandle( sizeof (GDevice) );°dONLNd5ü<™π*
  9122.     if (newDevice != nil)°dONLNdO©<¥U*
  9123.     {°dONLNdU≥<æ6*
  9124. 2        /* Allocate the embryonic inverse table */°dONLNdàΩ<»E*
  9125. 5        embryoITab = (ITabHandle)NewHandleClear( 2 );°dONLNdæ«<““*
  9126.         if (embryoITab != nil)°dONLNd›—<‹i*
  9127.             {°dONLNdÁ€<Ê^*
  9128. :            /* Set rectangle of device to PixMap bounds */°dONLNd"Â<'*
  9129. /            deviceRect = (**basePixMap).bounds;°dONLNdR˘<;*3            /* Initialize the new GDevice fields */°dONLNdÜ<¬*
  9130. N            (**newDevice).gdRefNum = 0;            /* Only used for screens */°dONLNd’
  9131. <≥*
  9132. K            (**newDevice).gdID = 0;                /* Won’t normally use */°dONLNd!<""*
  9133. .            if ((**basePixMap).pixelSize <= 8)°dONLNdP!<,Ω*
  9134. M                (**newDevice).gdType = clutType;   /* Depth≤8; clut device */°dONLNdû+<6å*
  9135.             else°dONLNdØ5<@«*
  9136. O                (**newDevice).gdType = directType; /* Depth>8; direct device */°dONLNdˇ?<J¬*
  9137. N            (**newDevice).gdITable = embryoITab;   /* 2-byte handle for now */°dONLNdNI<TΩ*
  9138. M            (**newDevice).gdResPref = kITabRes;    /* Normal inv table res */°dONLNdúS<^Ω*
  9139. M            (**newDevice).gdSearchProc = nil;      /* No color-search proc */°dONLNdÍ]<h≥*
  9140. K            (**newDevice).gdCompProc = nil;        /* No complement proc */°dONLNd6g<rΩ*
  9141. M            (**newDevice).gdFlags = 0;             /* Will set these later */°dONLNdÑq<|Ω*
  9142. M            (**newDevice).gdPMap = basePixMap;     /* Reference our PixMap */°dONLNd“{<Ü≥*
  9143. K            (**newDevice).gdRefCon = 0;            /* Won’t normally use */°dONLNd    Ö<ê∏*
  9144. L            (**newDevice).gdNextGD = nil;          /* Not in GDevice list */ ¡X¡
  9145. **2QD 13 - Principia Off-Screen Graphics Environments(÷˙21)
  9146.  of 51(ÏZM.QD.PrincipiaOffScreenˇû◊#ˇ ˇˇˇˇ#◊ 
  9147. IR,Times
  9148. .+6-Macintosh Technical Notes /4/˘,
  9149. Courier
  9150.     °dONLNd(û*N            (**newDevice).gdRect = deviceRect;     /* Use PixMap dimensions */°dONLNdO'2{*
  9151. G            (**newDevice).gdMode = -1;             /* For nonscreens */°dONLNdó1<û*
  9152. N            (**newDevice).gdCCBytes = 0;           /* Only used for screens */°dONLNdÊ;Fû*
  9153. N            (**newDevice).gdCCDepth = 0;           /* Only used for screens */°dONLNd5EPû*
  9154. N            (**newDevice).gdCCXData = 0;           /* Only used for screens */°dONLNdÑOZû*
  9155. N            (**newDevice).gdCCXMask = 0;           /* Only used for screens */°dONLNd”YdÖ*
  9156. I            (**newDevice).gdReserved = 0;          /* Currently unused */°dONLNdmxl*D            /* Set color-device bit if PixMap isn’t black & white */°dONLNdbwǢ*
  9157. -            if ((**basePixMap).pixelSize > 1)°dONLNdêÅå]*
  9158. A                SetDeviceAttribute( newDevice, gdDevType, true );°dONLNd“ï†ä*J            /* Set bit to indicate that the GDevice has no video driver */°dONLNdü™D*
  9159. <            SetDeviceAttribute( newDevice, noDriver, true );°dONLNdZ≥æ˛*.            /* Initialize the inverse table */°dONLNdâΩ»˛*
  9160. .            if ((**basePixMap).pixelSize <= 8)°dONLNd∏«“Y*
  9161.  
  9162.             {°dONLNdΔ—‹è*
  9163. K                MakeITable( (**basePixMap).pmTable, (**newDevice).gdITable,°dONLNd€Ê*
  9164. 2                        (**newDevice).gdResPref );°dONLNdEÂ¬*
  9165. "                error = QDError();°dONLNdhÔ˙Y*
  9166.  
  9167.             }°dONLNdv˘E*
  9168.             }°dONLNdÄT*
  9169.         else°dONLNdç
  9170. ≥*
  9171.             error = MemError();°dONLNd≠"1*
  9172.     }°dONLNd≥!,@*
  9173.     else°dONLNdº+6ü*
  9174.         error = MemError();°dONLNdÿ?JÂ*)    /* Handle any errors along the way */°dONLNdITã*
  9175.     if (error != noErr)°dONLNdS^1*
  9176.     {°dONLNd ]hÆ*
  9177.         if (embryoITab != nil)°dONLNd?gr*
  9178. /            DisposHandle( (Handle)embryoITab );°dONLNdoq|©*
  9179.         if (newDevice != nil)°dONLNdç{ܲ*
  9180. .            DisposHandle( (Handle)newDevice );°dONLNdºÖê1*
  9181.     }°dONLNd¬èö@*
  9182.     else°dONLNdÀô§∏*
  9183.          *retGDevice = newDevice;°dONLNdÏ≠∏Ù*,    /* Return a handle to the new GDevice */°dONLNd∑¬m*
  9184.     return error;°dONLNd+¡Ã*
  9185. }
  9186. °dONLNd-◊„ô*CreateGDevice begins by °dONLNdE◊ô„‡)Åallocating the 
  9187. °dONLNdT◊‡„
  9188. )GGDevice
  9189. °dONLNd[◊
  9190. „⁄)*' structure and an embryonic form of the°dONLNdɄԥ( 6#inverse table in the current heap. °dONLNd¶„¥Ô⁄)ú?The inverse table is allocated as two zero bytes for now; it’ll°dONLNdÊÔ˚=(6?be resized and initialized to be a real inverse table later in °dONLNd%Ô=˚⁄([this routine. Then, each of the
  9191. °dONLNdE˚B(#6GDevice
  9192. °dONLNdL˚B)*- fields are initialized as described earlier.    °dONLNdz.(;60After all the fields have been initialized, the 
  9193. °dONLNd™.X(;LgdFlags
  9194. °dONLNd±Xd)* 
  9195. °dONLNd≤d⁄) field is set through
  9196. °dONLNd«+ä(G6_SetDeviceAttribute
  9197. °dONLNd⁄ä+)r . If the desired pixel depth is °dONLNd˙+à)ägreater than 1, then the 
  9198. °dONLNdà+æ)t    gdDevType
  9199. °dONLNdæ+⁄)6 bit is°dONLNd$+7ï(S6set. This indicates that the 
  9200. °dONLNdA+ï7ø)}GDevice
  9201. °dONLNdH+ø7Ê)*
  9202.  is for a °dONLNdR+Ê7⁄)'2color graphics environment. This bit should be set°dONLNdÖ7CQ(_6Feven if a gray-scale color table is used for this off-screen graphics °dONLNdÀ7QC™(_oenvironment. The 
  9203. °dONLNd‹7™C⁄)YnoDriver
  9204. °dONLNdÂCO⁄(k6)bit is set because this is an off-screen 
  9205. °dONLNd    C⁄O)¬GDevice
  9206. °dONLNd    COT)* and so there’s °dONLNd    %CTO⁄)Pno associated video device°dONLNd    @O[8(w6driver.°dONLNd    Hgs3*Finall°dONLNd    Ng3s9)y°dONLNd    Og8sC)>, the inverse table is resized and initialized by calling the 
  9207. °dONLNd    çgCsÖ(èa _MakeITable
  9208. °dONLNd    ògÖsª)B  routine. A °dONLNd    §gªs⁄)6handle°dONLNd    ´s«(õ6\to the two-byte embryonic inverse table that was created earlier in CreateGDevice is passed °dONLNd
  9209. s«⁄(õÂas a°dONLNd
  9210. ãÿ(ß6cparameter, as is a handle to the off-screen color table and the preferred inverse-table resolution. ¡4¡˘
  9211. */22)
  9212.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ<◊#ˇ ˇˇˇˇ#◊ 
  9213. IR,Times
  9214. .+Z-Developer Support Center(-Ï
  9215. March 1992 /X/
  9216. °dONLNd<)å(EZ
  9217. All Fall Down°dONLNd5<A≈*RNow that we have a way to create an off-screen graphics environment, there has to °dONLNd`5≈A˛(]„ be a way to°dONLNdlA<Me(iZget rid °dONLNdtAeM˛))Iof it too. The DisposeOffScreen routine shown in Listing 4 does this. The°dONLNdæM<YÁ(uZVCreateOffScreen routine returns an off-screen graphics environment that’s represented °dONLNdMÁY˛(uby a,
  9218. Courier
  9219. °dONLNdY<er(ÅZ    CGrafPort
  9220. °dONLNd"Yreu)6 °dONLNd#Yueä)and 
  9221. °dONLNd'Yäe¥)GDevice
  9222. °dONLNd.Y¥e≥)*4. The DisposeOffScreen routine takes the off-screen 
  9223. °dONLNdbY≥eÈ)ˇ    CGrafPort
  9224. °dONLNdkYÈe˛)6 and
  9225. °dONLNdpe<qf(çZGDevice
  9226. °dONLNdwefq})* and °dONLNd|e}q»)Edeallocates all the memory that’s associated with them including the 
  9227. °dONLNd¡e»q˛(çÊ    CGrafPort
  9228. °dONLNdÀq<}◊(ôZ"and its dependent structures, the 
  9229. °dONLNdÌq◊})õGDevice
  9230. °dONLNdÙq})*, the 
  9231. °dONLNd˙q}=)PixMap
  9232. °dONLNdq=}Ò)$), the color table, and the inverse table.°dONLNd*â<ï∫(±ZMPW Pascal Listing 4
  9233.     °dONLNd?°<¨√*PROCEDURE DisposeOffScreen(°dONLNd[´<∂≥*
  9234. K   doomedPort:    CGrafPtr; {Pointer to the CGrafPort we’re getting rid of}°dONLNdßµ<¿§*
  9235. H   doomedGDevice: GDHandle  {Handle to the GDevice we’re getting rid of}°dONLNdø< U*
  9236.    );°dONLNdˆ”<fiZ*   VAR°dONLNd˝›<Ë^*
  9237. :      currPort:    CGrafPtr; {Pointer to the current port}°dONLNd8Á<Úh*
  9238. <      currGDevice: GDHandle; {Handle to the current GDevice}°dONLNdu˚<U*BEGIN°dONLNd{<ö*
  9239. F   (* Check to see whether the doomed CGrafPort is the current port *)°dONLNd¬<“*
  9240.    GetPort(GrafPtr(currPort));°dONLNd·<$‹*
  9241.     IF currPort = doomedPort THEN°dONLNd#<.s*
  9242.       BEGIN°dONLNd-<8Ü*
  9243. B         (* It is; set current port to Window Manager CGrafPort *)°dONLNdQ7<B‹*
  9244.           GetCWMgrPort(currPort);°dONLNdrA<L*
  9245. $         SetPort(GrafPtr(currPort));°dONLNdóK<Vn*
  9246.  
  9247.       END;°dONLNd¢_<jü*G   (* Check to see whether the doomed GDevice is the current GDevice *)°dONLNdÍi<tÕ*
  9248.    currGDevice := GetGDevice;°dONLNds<~˙*
  9249. &   IF currGDevice = doomedGDevice THEN°dONLNd/}<àã*
  9250. C      (* It is; set current GDevice to the main screen’s GDevice *)°dONLNdsá<í‹*
  9251.        SetGDevice(GetMainDevice);°dONLNdîõ<¶“*   (* Throw everything away *)°dONLNd≥•<∞·*
  9252. !   doomedGDevice^^.gdPMap := NIL;°dONLNd’Ø<∫‹*
  9253.     DisposGDevice(doomedGDevice);°dONLNdˆπ<ƒ,*
  9254. 0   DisposPtr(doomedPort^.portPixMap^^.baseAddr);°dONLNd'√<Œ6*
  9255. 2   IF doomedPort^.portPixMap^^.pmTable <> NIL THEN°dONLNdZÕ<ÿE*
  9256. 5      DisposCTable(doomedPort^.portPixMap^^.pmTable);°dONLNdê◊<‚æ*
  9257.    CloseCPort(doomedPort);°dONLNd´·<Ï“*
  9258.    DisposPtr(Ptr(doomedPort));°dONLNd Î<ˆP*
  9259. END;
  9260. °dONLNdœ<
  9261. ü*MPW C Listing 4
  9262.     °dONLNdfl<$™*void DisposeOffScreen(°dONLNdˆ#<.∏*
  9263. L    CGrafPtr doomedPort,    /* Pointer to the CGrafPort to be disposed of */°dONLNdC-<8©*
  9264. I    GDHandle doomedGDevice) /* Handle to the GDevice to be disposed of */°dONLNdç7<BA*
  9265. {°dONLNdèA<Lc*
  9266. ;    CGrafPtr currPort;    /* Pointer to the current port */°dONLNdÀK<Vm*
  9267. =    GDHandle currGDevice; /* Handle to the current GDevice */°dONLNd    _<jü*G    /* Check to see whether the doomed CGrafPort is the current port */°dONLNdQi<t*
  9268. $    GetPort( (GrafPtr *)&currPort );°dONLNdvs<~◊*
  9269.     if (currPort == doomedPort)°dONLNdñ}<àU*
  9270.     { ¡X¡
  9271. *22QD 13 - Principia Off-Screen Graphics Environments(÷˙23)
  9272.  of 51(ÏZM.QD.PrincipiaOffScreenˇ÷◊#ˇ ˇˇˇˇ#◊ 
  9273. IR,Times
  9274. .+6-Macintosh Technical Notes /4/˘,
  9275. Courier
  9276.     °dONLNd(]*A        /* It is; set current port to Window Manager CGrafPort */°dONLNdB'2¬*
  9277. "        GetCWMgrPort( &currPort );°dONLNde1<—*
  9278. %        SetPort( (GrafPtr)currPort );°dONLNdã;F1*
  9279.     }°dONLNdëOZÄ*H    /* Check to see whether the doomed GDevice is the current GDevice */°dONLNd⁄Yd≥*
  9280.     currGDevice = GetGDevice();°dONLNd˙cn—*
  9281. %    if (currGDevice == doomedGDevice)°dONLNd mxq*
  9282. E        /* It is; set current GDevice to the main screen’s GDevice */°dONLNdfwÇ÷*
  9283. &        SetGDevice( GetMainDevice() );°dONLNdçãñ≥*    /* Throw everything away */°dONLNd≠*
  9284. #    (**doomedGDevice).gdPMap = nil;°dONLNd—ü™«*
  9285. #    DisposGDevice( doomedGDevice );°dONLNdı©¥!*
  9286. 5    DisposPtr( (**doomedPort->portPixMap).baseAddr );°dONLNd+≥æ*
  9287. 2    if ((**doomedPort->portPixMap).pmTable != nil)°dONLNd^Ω»?*
  9288. ;        DisposCTable( (**doomedPort->portPixMap).pmTable );°dONLNdö«“©*
  9289.     CloseCPort( doomedPort );°dONLNd∏—‹Ω*
  9290. !    DisposPtr( (Ptr)doomedPort );°dONLNd⁄€Ê*
  9291. }
  9292. °dONLNd‹Ò˝a*>One mildly tricky aspect of this is that we shouldn’t dispose °dONLNdÒa˝⁄(of the current graphics°dONLNd2˝    A(%6Aenvironment. To prevent this, the current port is retrieved by a °dONLNds˝A    b(%_call to 
  9293. °dONLNd{˝b    í)!_GetPort
  9294. °dONLNdÉ˝í    ⁄)0. If it returns a°dONLNdï    t(16pointer to the same °dONLNd©    t⁄)\Lport that DisposeOffScreen is disposing, then the current port is set to the°dONLNdˆ!(=6Window Manager’s 
  9295. °dONLNd!µ)g    CGrafPort
  9296. °dONLNdµ!ò)6-. That was an arbitrary choice, but it’s the °dONLNd=ò!⁄)„
  9297. most neutral.°dONLNdK!-=(I6Similarl°dONLNdS!=-C)%y°dONLNdT!B-Z), the °dONLNdZ!Z-)current 
  9298. °dONLNdb!-©)%GDevice
  9299. °dONLNdi!©- )* is retrieved by a call to 
  9300. °dONLNdÑ! -b)w _GetGDevice
  9301. °dONLNdè!b-⁄)B. If it returns a handle to°dONLNd´-9D(U6    the same 
  9302. °dONLNd¥-D9n),GDevice
  9303. °dONLNdª-n9Ö)* that °dONLNd¡-Ö9⁄)GDisposeOffScreen is disposing, then the current port is set to the main°dONLNd    9EB(a6    screen’s 
  9304. °dONLNd9BEl)*GDevice
  9305. °dONLNd9lE„)*. Again, that’s an arbitrar°dONLNd49„EÈ)wy°dONLNd59ËE4), neutral choice.°dONLNdGQ]o(y6The inverse table, 
  9306. °dONLNdZQo]ô)WGDevice
  9307. °dONLNdaQô]›)*, pixel image, °dONLNdpQ›]⁄)D4and color table are disposed of. Before disposing of°dONLNd•]iê(Ö6Othe color table, a check is first made to see whether it’s NIL. That’s because °dONLNdÙ]êi⁄(ÖÆit’s reasonable,°dONLNdiuù(ë6though not normal, for the 
  9308. °dONLNd iùu¡)ÖPixMap
  9309. °dONLNd&i¡uˇ)$
  9310.  not to have °dONLNd3iˇu⁄)>,even a dummy color table if the direct-color°dONLNd`uÅ©(ù6model is being used. Then the 
  9311. °dONLNd~u©Åfl)ë    CGrafPort
  9312. °dONLNdáuflÅ‚)6 °dONLNdàu‚Å⁄)5is closed which deallocates all the pieces associated°dONLNdæÅçE(©6    with the 
  9313. °dONLNd«ÅEç{)-    CGrafPort
  9314. °dONLNd–Å{ç»)6, including the 
  9315. °dONLNd‡Å»çÏ)MPixMap
  9316. °dONLNdÊÅÏçx)$. Once this is done, all the °dONLNdÅxç⁄)åstructures that were°dONLNdçô(µ63created by calling CreateOffScreen are deallocated.
  9317. °dONLNdL±¿†*'Playing With Blocks
  9318. °dONLNd`Ãÿh*Now that these °dONLNdoÃhÿ⁄)PHfour routines with two entry points can create and dispose of off-screen°dONLNd∏ÿ‰œ(6$graphics environments, how are they °dONLNd‹ÿœ‰⁄)∑5used? There are several phases to using an off-screen°dONLNd‰˛( 60graphics environment: creating it, drawing into °dONLNdB‰˛⁄)Ê-it, switching between it and other off-screen°dONLNdp¸¿(6Rand on-screen graphics environments, copying images to and from it, and disposing °dONLNd¬¿¸⁄(fiof it.°dONLNd…¸ò($6Listing 5 shows a routine °dONLNd„¸ò⁄)Ä@called ExerciseOffScreen which is a very basic example of all of°dONLNd    $W(06
  9319. these phases.°dONLNd    2 ,ñ*MPW Pascal Listing 5
  9320.     °dONLNd    G8C§*PROCEDURE ExerciseOffScreen;°dONLNd    dLW@*   CONST°dONLNd    mVaô*
  9321. M      kOffDepth  = 8;    {Number of bits per pixel in off-screen environment}°dONLNd    ª`k5*
  9322. 9      rGrayClut  = 1600; {Resource ID of gray-scale clut}°dONLNd    ıju5*
  9323. 9      rColorClut = 1601; {Resource ID of full-color clut} ¡4¡˘
  9324. *E24)
  9325.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ6◊#ˇ ˇˇˇˇ#◊ 
  9326. IR,Times
  9327. .+Z-Developer Support Center(-Ï
  9328. March 1992 /X/,
  9329. Courier
  9330.     °dONLNd<(Z(DZ   VAR°dONLNd'<2©*
  9331. I      grayPort:    CGrafPtr;   {Graphics environment for gray off screen}°dONLNdQ1<<ö*
  9332. F      grayDevice:  GDHandle;   {Color environment for gray off screen}°dONLNdò;<FÆ*
  9333. J      colorPort:   CGrafPtr;   {Graphics environment for color off screen}°dONLNd„E<Pü*
  9334. G      colorDevice: GDHandle;   {Color environment for color off screen}°dONLNd+O<ZÆ*
  9335. J      savedPort:   GrafPtr;    {Pointer to the saved graphics environment}°dONLNdvY<dö*
  9336. F      savedDevice: GDHandle;   {Handle to the saved color environment}°dONLNdΩc<nã*
  9337. C      offColors:   CTabHandle; {Colors for off-screen environments}°dONLNdm<xï*
  9338. E      offRect:     Rect;       {Rectangle of off-screen environments}°dONLNdGw<Çr*
  9339. >      circleRect:  Rect;       {Rectangles for circle-drawing}°dONLNdÜÅ<å,*
  9340. 0      count:       Integer;    {Generic counter}°dONLNd∑ã<ñÜ*
  9341. B      aColor:      RGBColor;   {Color used for drawing off screen}°dONLNd˙ï<†ö*
  9342. F      error:       OSErr;      {Error return from off-screen creation}°dONLNdA©<¥U*BEGIN°dONLNdG≥<æö*
  9343. F   (* Set up the rectangle for the off-screen graphics environments *)°dONLNdéΩ<»*
  9344. $   SetRect(offRect, 0, 0, 256, 256);°dONLNd≥—<‹©*I   (* Get the color table for the gray off-screen graphics environment *)°dONLNd˝€<Êı*
  9345. %   offColors := GetCTable(rGrayClut);°dONLNd#Ô<˙T*8   (* Create the gray off-screen graphics environment *)°dONLNd\˘<ê*
  9346. D   error := CreateOffScreen(offRect, kOffDepth, offColors, grayPort,°dONLNd°<•*
  9347.          grayDevice);°dONLNd∑<"¥*   IF error = noErr THEN°dONLNd–!<,s*
  9348.       BEGIN°dONLNd‹+<6Ã*
  9349. P         (* Get the color table for the color off-screen graphics environment *)°dONLNd-5<@*
  9350. ,         offColors := GetCTable(rColorClut);°dONLNdZI<Tw*?         (* Create the color off-screen graphics environment *)°dONLNdöS<^≥*
  9351. K         error := CreateOffScreen(offRect, kOffDepth, offColors, colorPort,°dONLNdÊ]<h»*
  9352.                colorDevice);°dONLNdq<|“*         IF error = noErr THEN°dONLNd"{<Üë*
  9353.             BEGIN°dONLNd4Ö<ê^*
  9354. :               (* Save the current graphics environment *)°dONLNdoè<öÊ*
  9355. "               GetPort(savedPort);°dONLNdíô<§    *
  9356. )               savedDevice := GetGDevice;°dONLNdº≠<∏©*I               (* Set the current graphics environment to the gray one *)°dONLNd∑<¬*
  9357. *               SetPort(GrafPtr(grayPort));°dONLNd1¡<Ã˙*
  9358. &               SetGDevice(grayDevice);°dONLNdX’<‡¬*N               (* Draw gray-scale ramp into the gray off-screen environment *)°dONLNdßfl<͡*
  9359. '               FOR count := 0 TO 255 DO°dONLNdœÈ<ÙØ*
  9360.                   BEGIN°dONLNdÁÛ<˛'*
  9361. /                     aColor.red := count * 257;°dONLNd˝<,*
  9362. 0                     aColor.green := aColor.red;°dONLNdH<1*
  9363. 1                     aColor.blue := aColor.green;°dONLNdz<*
  9364. *                     RGBForeColor(aColor);°dONLNd•<&˙*
  9365. &                     MoveTo(0, count);°dONLNdÃ%<0*
  9366. (                     LineTo(255, count);°dONLNdı/<:™*
  9367.                   END;°dONLNd     C<N¬*N               (* Copy gray ramp into color off-screen colorized with green *)°dONLNd    [M<X*
  9368. +               SetPort(GrafPtr(colorPort));°dONLNd    áW<bˇ*
  9369. '               SetGDevice(colorDevice);°dONLNd    Øa<lÃ*
  9370. P               aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;°dONLNd
  9371. k<v*
  9372. $               RGBForeColor(aColor);°dONLNd
  9373. %u<Ä@*
  9374. 4               CopyBits(GrafPtr(grayPort)^.portBits,°dONLNd
  9375. Z<ä6*
  9376. 2                     GrafPtr(colorPort)^.portBits,°dONLNd
  9377. çâ<î*
  9378. (                     grayPort^.portRect, ¡X¡
  9379. *&2QD 13 - Principia Off-Screen Graphics Environments(÷˙25)
  9380.  of 51(ÏZM.QD.PrincipiaOffScreenˇT◊#ˇ ˇˇˇˇ#◊ 
  9381. IR,Times
  9382. .+6-Macintosh Technical Notes /4/˘,
  9383. Courier
  9384.     °dONLNd(Â*)                     colorPort^.portRect,°dONLNd*'2*
  9385. 0                     srcCopy + ditherCopy, NIL);°dONLNd[;F&*6               (* Draw red, green, and blue circles *)°dONLNdíEP©*
  9386.                PenSize(8, 8);°dONLNd∞OZ®*
  9387. P               aColor.red := $FFFF; aColor.green := $0000; aColor.blue := $0000;°dONLNdYdÃ*
  9388. $               RGBForeColor(aColor);°dONLNd&cn
  9389. *
  9390. 1               circleRect := colorPort^.portRect;°dONLNdXmx—*
  9391. %               FrameOval(circleRect);°dONLNd~wÇ®*
  9392. P               aColor.red := $0000; aColor.green := $FFFF; aColor.blue := $0000;°dONLNdœÅåÃ*
  9393. $               RGBForeColor(aColor);°dONLNdÙãñ˘*
  9394. -               InsetRect(circleRect, 20, 20);°dONLNd"*
  9395. %               FrameOval(circleRect);°dONLNdHü™®*
  9396. P               aColor.red := $0000; aColor.green := $0000; aColor.blue := $FFFF;°dONLNdô©¥Ã*
  9397. $               RGBForeColor(aColor);°dONLNdæ≥æ˘*
  9398. -               InsetRect(circleRect, 20, 20);°dONLNdÏΩ»—*
  9399. %               FrameOval(circleRect);°dONLNd—‹û*N               (* Copy the color off-screen environment to the current port *)°dONLNda€ʬ*
  9400. "               SetPort(savedPort);°dONLNdÑÂ€*
  9401. '               SetGDevice(savedDevice);°dONLNd¨Ô˙ä*
  9402. J               CopyBits(GrafPtr(colorPort)^.portBits, savedPort^.portBits,°dONLNd˜˘N*
  9403. >                     colorPort^.portRect, savedPort^.portRect,°dONLNd6«*
  9404. #                     srcCopy, NIL);°dONLNdZ"l*D               (* Dispose of the off-screen graphics environments *)°dONLNdü!,&*
  9405. 6               DisposeOffScreen(grayPort, grayDevice);°dONLNd÷+60*
  9406. 8               DisposeOffScreen(colorPort, colorDevice);°dONLNd5@h*
  9407.             END;°dONLNd ?JJ*
  9408.  
  9409.       END;°dONLNd+IT,*
  9410. END;
  9411. °dONLNd0_k{*MPW C Listing 5
  9412.     °dONLNd@wÇ®*P#define kOffDepth  8    /* Number of bits per pixel in off-screen environment */°dONLNdëÅåD*
  9413. <#define rGrayClut  1600 /* Resource ID of gray-scale clut */°dONLNdŒãñD*
  9414. <#define rColorClut 1601 /* Resource ID of full-color clut */°dONLNd ü™ê*void ExerciseOffScreen()°dONLNd$©¥*
  9415. {°dONLNd&≥æä*
  9416. J    CGrafPtr   grayPort;    /* Graphics environment for gray off screen */°dONLNdqΩ»{*
  9417. G    GDHandle   grayDevice;  /* Color environment for gray off screen */°dONLNdπ«“è*
  9418. K    CGrafPtr   colorPort;   /* Graphics environment for color off screen */°dONLNd—‹Ä*
  9419. H    GDHandle   colorDevice; /* Color environment for color off screen */°dONLNdN€Êè*
  9420. K    GrafPtr    savedPort;   /* Pointer to the saved graphics environment */°dONLNdöÂ{*
  9421. G    GDHandle   savedDevice; /* Handle to the saved color environment */°dONLNd‚Ô˙l*
  9422. D    CTabHandle offColors;   /* Colors for off-screen environments */°dONLNd'˘v*
  9423. F    Rect       offRect;     /* Rectangle of off-screen environments */°dONLNdnS*
  9424. ?    Rect       circleRect;  /* Rectangles for circle-drawing */°dONLNdÆ
  9425. 
  9426. *
  9427. 1    short      count;       /* Generic counter */°dONLNd‡"g*
  9428. C    RGBColor   aColor;      /* Color used for drawing off screen */°dONLNd    $!,{*
  9429. G    OSErr      error;       /* Error return from off-screen creation */°dONLNd    l5@{*G    /* Set up the rectangle for the off-screen graphics environments */°dONLNd    ¥?J‡*
  9430. (    SetRect( &offRect, 0, 0, 256, 256 );°dONLNd    ›S^ä*J    /* Get the color table for the gray off-screen graphics environment */°dONLNd
  9431. (]h€*
  9432. '    offColors = GetCTable( rGrayClut );°dONLNd
  9433. Pq|5*9    /* Create the gray off-screen graphics environment */°dONLNd
  9434. ä{ÜD*
  9435. <    error = CreateOffScreen( &offRect, kOffDepth, offColors,°dONLNd
  9436. «Öê—*
  9437. %            &grayPort, &grayDevice ); ¡4¡˘
  9438. **26)
  9439.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ:◊#ˇ ˇˇˇˇ#◊ 
  9440. IR,Times
  9441. .+Z-Developer Support Center(-Ï
  9442. March 1992 /X/,
  9443. Courier
  9444.     °dONLNd'<2Ø(NZ    if (error == noErr)°dONLNd1<<U*
  9445.     {°dONLNd;<F«*
  9446. O        /* Get the color table for the color off-screen graphics environment */°dONLNdnE<P*
  9447. ,        offColors = GetCTable( rColorClut );°dONLNdõY<dr*>        /* Create the color off-screen graphics environment */°dONLNd⁄c<n|*
  9448. @        error = CreateOffScreen( &offRect, kOffDepth, offColors,°dONLNdm<x*
  9449. +                &colorPort, &colorDevice );°dONLNdGÅ<å√*        if (error == noErr)°dONLNdcã<ñi*
  9450.             {°dONLNdmï<†O*
  9451. 7            /* Save the current graphics environment */°dONLNd•ü<™Ê*
  9452. "            GetPort( &savedPort );°dONLNd»©<¥ˇ*
  9453. '            savedDevice = GetGDevice();°dONLNdΩ<»ö*F            /* Set the current graphics environment to the gray one */°dONLNd7«<“    *
  9454. )            SetPort( (GrafPtr)grayPort );°dONLNda—<‹ı*
  9455. %            SetGDevice( grayDevice );°dONLNdáÂ<≥*K            /* Draw gray-scale ramp into the gray off-screen environment */°dONLNd”Ô<˙1*
  9456. 1            for (count = 0; count < 256; ++count)°dONLNd˘<}*
  9457.  
  9458.             {°dONLNd<ö*
  9459. F                aColor.red = aColor.green = aColor.blue = count * 257;°dONLNdZ
  9460. <*
  9461. (                RGBForeColor( &aColor );°dONLNdÉ<"Î*
  9462. #                MoveTo( 0, count );°dONLNdß!<,ı*
  9463. %                LineTo( 255, count );°dONLNdÕ+<6}*
  9464.  
  9465.             }°dONLNd€?<J≥*K            /* Copy gray ramp into color off-screen colorized with green */°dONLNd'I<T*
  9466. *            SetPort( (GrafPtr)colorPort );°dONLNdRS<^˙*
  9467. &            SetGDevice( colorDevice );°dONLNdy]<hΩ*
  9468. M            aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;°dONLNd«g<r*
  9469. $            RGBForeColor( &aColor );°dONLNdÏq<|E*
  9470. 5            CopyBits( &((GrafPtr)grayPort)->portBits,°dONLNd"{<Ü@*
  9471. 4                    &((GrafPtr)colorPort)->portBits,°dONLNdWÖ<ê*
  9472. (                    &grayPort->portRect,°dONLNdÄè<ö    *
  9473. )                    &colorPort->portRect,°dONLNd™ô<§,*
  9474. 0                    srcCopy | ditherCopy, nil );°dONLNd€≠<∏;*3            /* Draw red, green, and blue circles */°dONLNd∑<¬»*
  9475.             PenSize( 8, 8 );°dONLNd,¡<ÃΩ*
  9476. M            aColor.red = 0xFFFF; aColor.green = 0x0000; aColor.blue = 0x0000;°dONLNdzÀ<÷*
  9477. $            RGBForeColor( &aColor );°dONLNdü’<‡*
  9478. -            circleRect = colorPort->portRect;°dONLNdÕfl<Íı*
  9479. %            FrameOval( &circleRect );°dONLNdÛÈ<ÙΩ*
  9480. M            aColor.red = 0x0000; aColor.green = 0xFFFF; aColor.blue = 0x0000;°dONLNdAÛ<˛*
  9481. $            RGBForeColor( &aColor );°dONLNdf˝<*
  9482. -            InsetRect( &circleRect, 20, 20 );°dONLNdî<ı*
  9483. %            FrameOval( &circleRect );°dONLNd∫<Ω*
  9484. M            aColor.red = 0x0000; aColor.green = 0x0000; aColor.blue = 0xFFFF;°dONLNd<&*
  9485. $            RGBForeColor( &aColor );°dONLNd-%<0*
  9486. -            InsetRect( &circleRect, 20, 20 );°dONLNd[/<:ı*
  9487. %            FrameOval( &circleRect );°dONLNdÅC<N≥*K            /* Copy the color off-screen environment to the current port */°dONLNdÕM<X·*
  9488. !            SetPort( savedPort );°dONLNdÔW<b˙*
  9489. &            SetGDevice( savedDevice );°dONLNd    a<l∏*
  9490. L            CopyBits( &((GrafPtr)colorPort)->portBits, &savedPort->portBits,°dONLNd    ck<vw*
  9491. ?                    &colorPort->portRect, &savedPort->portRect,°dONLNd    £u<ÄÎ*
  9492. #                    srcCopy, nil ); ¡X¡
  9493. *:2QD 13 - Principia Off-Screen Graphics Environments(÷˙27)
  9494.  of 51(ÏZM.QD.PrincipiaOffScreenˇí◊#ˇ ˇˇˇˇ#◊ 
  9495. IR,Times
  9496. .+6-Macintosh Technical Notes /4/˘,
  9497. Courier
  9498.     °dONLNd(]*A            /* Dispose of the off-screen graphics environments */°dONLNdB'2!*
  9499. 5            DisposeOffScreen( grayPort, grayDevice );°dONLNdx1<+*
  9500. 7            DisposeOffScreen( colorPort, colorDevice );°dONLNd∞;FE*
  9501.             }°dONLNd∫EP1*
  9502.     }°dONLNd¿OZ*
  9503. }
  9504. °dONLNd¬eq_*?Two off-screen graphics environments are created in the same wa°dONLNde_qe(ç}y°dONLNdedq»). A rectangle that’s °dONLNde»q⁄)d256°dONLNdq}(ô65pixels wide by 256 pixels high and with its top-left °dONLNdPq}⁄(ô=&coordinate at (0, 0) is created in the
  9505. °dONLNdw}âB(•6offRect
  9506. °dONLNd~}Bâ¶)* local variable. 'clut' °dONLNdñ}¶â⁄)d@resources are loaded from the application’s resource fork to use°dONLNd◊âï6(±6as the °dONLNdfiâ6ï⁄)Zcolor tables of the two off-screen graphics environments; a gray-scale 'clut' in the first°dONLNd9ï°1(Ω6case °dONLNd>ï1°⁄)Tand a full-color 'clut' in the second case. Then, CreateOffScreen is called with the°dONLNdì°≠t(…6Mrectangle, color table, and a hard-coded pixel depth of eight bits per pixel.°dONLNd·π≈ò*If CreateOffScreen returns 
  9507. °dONLNd¸πò≈∂)ÄnoErr
  9508. °dONLNdπ∂≈t)* in both cases, then the current graphics °dONLNd+πt≈⁄)æenvironment is saved°dONLNd@≈—Q(Ì6@so that it can be restored later. Graphics environments consist °dONLNdÄ≈Q—⁄(Ìoof the current port and the°dONLNdú—›=(˘6current 
  9509. °dONLNd§—=›g)%GDevice
  9510. °dONLNd´—g›™)*. The current 
  9511. °dONLNdπ—™›⁄)CGrafPort
  9512. °dONLNd¡—⁄›Ï)0 or 
  9513. °dONLNd≈—Ï›")    CGrafPort
  9514. °dONLNdŒ—"›j)6 is saved with 
  9515. °dONLNd›—j›ö)H_GetPort
  9516. °dONLNd—ö›¢)0. °dONLNdÁ—¢›⁄) The current
  9517. °dONLNdÛ›ÈB(6GDevice
  9518. °dONLNd˙›BÈÜ)* is saved with 
  9519. °dONLNd    ›ÜÈ»)D _GetGDevice
  9520. °dONLNd›»ÈÃ)B.°dONLNdıŒ(6ZThe gray-scale off-screen graphics environment is set as the current graphics environment °dONLNdpıŒ⁄(Ïby°dONLNds
  9521. ;()6calling 
  9522. °dONLNd{;
  9523. k)#_SetPort
  9524. °dONLNdÉk
  9525. ó)0
  9526.  with its 
  9527. °dONLNdçó
  9528. Õ),    CGrafPort
  9529. °dONLNdñÕ
  9530.     )6
  9531.  and calling 
  9532. °dONLNd£    
  9533. K)< _SetGDevice
  9534. °dONLNdÆK
  9535. h)B with °dONLNd¥h
  9536. x)its 
  9537. °dONLNd∏x
  9538. ¢)GDevice
  9539. °dONLNdø¢
  9540. ⁄)* . A vertical°dONLNdÃ
  9541. 2(56;gray ramp is drawn into this graphics environment with the °dONLNd
  9542. 2⁄(5P"usual set of QuickDraw calls. This°dONLNd*%≤(A6Ographics environment’s pixel image is then copied to the full-color off-screen °dONLNdy≤%⁄(A–graphics°dONLNdÇ%1Å(M6Kenvironment with dithering and colorization with green (dithering requires °dONLNdÕ%Å1⁄(Mü32-Bit QuickDraw°dONLNdfi1=-(Y6and °dONLNd‚1-=⁄)Xconsistent colorization requires system software version 7.0; both of these features are°dONLNd;=I (e66described in Konstantin Othmer’s article “QuickDraw’s °dONLNdq= I⁄(e>$CopyBits Procedure: Better Than Ever°dONLNdñIU%(q6in °dONLNdôI%U≠)
  9543. System 7.0” in Issue 6 of °dONLNd≥I≠U“)àdevelop°dONLNd∫I“U⁄)%6). Before this copy happens, the full-color off-screen°dONLNdÒUa±(}6graphics environment must be °dONLNdU±aé)ô+set as the current one. Once this is done, 
  9544. °dONLNd9Uéaƒ)›    _CopyBits
  9545. °dONLNdBUƒa⁄)6 can°dONLNdGamz(â6properly map colors °dONLNd[azm⁄)bIfrom the gray-scale off-screen graphics environment to the full-color one°dONLNd•myÆ(ï6which gets a green ramp image.°dONLNdƒÖëH*;Red, green, and blue concentric circles are drawn into the °dONLNdˇÖHë⁄(≠ffull-color off-screen graphics°dONLNdëùV(π6 environment °dONLNd*ëVù⁄)>Oover the green ramp. This image is then copied to the graphics environment that°dONLNdzù©C(≈6was the °dONLNdÇùC©⁄)+Mcurrent one when ExerciseOffScreen was called. To do this, the saved graphics°dONLNd–©µï(—6Renvironment is set as the current one by what should now be the familiar calls to 
  9546. °dONLNd    "©ïµ≈(—≥_SetPort
  9547. °dONLNd    *©≈µ⁄)0 and
  9548. °dONLNd    /µ¡Z(›6 _SetGDevice
  9549. °dONLNd    :µZ¡¨)B. The off-screen °dONLNd    Kµ¨¡⁄)R;image is then copied to the saved graphics environment with
  9550. °dONLNd    á¡ÕN(È6    _CopyBits
  9551. °dONLNd    ê¡NÕR)6.°dONLNd    íŸ±(6Finally, the two off-screen °dONLNd    ÆŸ±Â⁄)ô4graphics environments are disposed of by calling the°dONLNd    „ÂÒ«(
  9552. 6]DisposeOffScreen routine that’s defined in the section “All Fall Down”  earlier in this Note.
  9553. °dONLNd
  9554. A    £*'Put That Checkbook °dONLNd
  9555. T    £Æ)ãA°dONLNd
  9556. U    ≠Õ)
  9557. way!
  9558. °dONLNd
  9559. Z$0x(L6>The previous section covered the basics of creating and using °dONLNd
  9560. ò$x0⁄(Lñoff-screen graphics°dONLNd
  9561. ¨0<Ó(X6)environments. This is good enough for man°dONLNd
  9562. ’0Ó<Ù)÷y°dONLNd
  9563. ÷0Û<ô)#, if not most, needs of off-screen °dONLNd
  9564. ˘0ô<⁄)¶ drawing. But°dONLNd <Hˆ(d61there are variations to creating and maintaining °dONLNd 7<ˆH⁄)fi/an off-screen graphics environment for specific°dONLNd gHTC(p6=cases. This section discusses a few of the more common cases.°dONLNd •`lÀ*About That Creation Thing . . .°dONLNd ≈xÑÃ*VThe CreateOffScreen routine, defined in Listing 1, takes three pieces of information: °dONLNd xÃÑ⁄(†Íthe°dONLNd ÑêÄ(¨6Nboundary rectangle, the desired pixel depth, and the desired color table. But °dONLNd mÑÄê⁄(¨ûthere’s much more ¡4¡˘
  9565. (÷628)
  9566.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇv◊#ˇ ˇˇˇˇ#◊ 
  9567. IR,Times
  9568. .+Z-Developer Support Center(-Ï
  9569. March 1992 /X/
  9570. °dONLNd<)◊(EZRto these pieces than ExerciseOffScreen shows. This section describes these pieces °dONLNdR◊)˛(Eıin more°dONLNdZ)<5Y(QZdetail.°dONLNdbA<Mı*'The first parameter to CreateOffScreen °dONLNdâAıM˛)π7is a rectangle which determines the size and coordinate°dONLNd¡M<Y=(uZ5system of the off-screen graphics environment. Usuall°dONLNdˆM=YC(u[y°dONLNd˜MBY†), the top-left corner °dONLNd
  9571. M†Y˛)^of the rectangle has°dONLNd"Y<eŸ(ÅZ#the coordinate (0, 0) because it’s °dONLNdEYŸe˛)ù=usually easiest to draw everything using coordinates that can°dONLNdÉe<q‚(çZ^also be thought of as the horizontal and vertical distance in pixels from the top-left corner °dONLNd·e‚q˛(çof the°dONLNdËq<}ò(ôZFgraphics environment. But in some cases, it’s more convenient to have °dONLNd.qò}˛(ô∂the (0, 0) coordinate°dONLNdD}<âÃ(•ZRsomewhere else, and passing CreateOffScreen a rectangle with a nonzero coordinate °dONLNdñ}Ãâ˙(•Í
  9572. in the top°dONLNd†}˙â˛).-°dONLNd°â<ï (±Zleft corner is an easy way to °dONLNdøâ ï˙)é>do this. The coordinate system can be translated after the off°dONLNd˝â˙ï˛(±-°dONLNd˛ï<°:(ΩZ4screen graphics environment is created by using the ,
  9573. Courier
  9574. °dONLNd2ï:°v)˛
  9575. _SetOrigin
  9576. °dONLNd<ïv°˛)< routine that’s described on°dONLNdY°<≠π(…Zpages 153 through 155 of °dONLNdr°π≠
  9577. )}Inside Macintosh °dONLNdɰ
  9578. ≠)TV°dONLNdѰ≠<)olume I.°dONLNdçπ<≈p(·ZWarning:°dONLNdñπÑ≈ï)HAs °dONLNdôπï≈Î)Inside Macintosh °dONLNd™πÎ≈Û)VV°dONLNd´πÚ≈Ω)*olume I, page 154, notes, the clip region °dONLNd’πΩ≈⁄)Àof the°dONLNd‹≈Ñ—õ(Ì¢port °dONLNd·≈õ—ç)0“sticks” to the coordinate system when you call 
  9579. °dONLNd≈ç—…)Ú
  9580. _SetOrigin
  9581. °dONLNd≈…—⁄)<. If
  9582. °dONLNd —Ñ›¿(˘¢
  9583. _SetOrigin
  9584. °dONLNd*—¿›≥)<2 offsets the coordinate system by a large amount, °dONLNd\—≥›⁄)Ûthen the°dONLNde›ÑÈô(¢clip °dONLNdj›ôÈ⁄)>region might be moved completely outside of the port’s drawing°dONLNd©ÈÑı(¢area, and nothing can °dONLNdøÈı⁄)Ä&be drawn into that port. After calling
  9585. °dONLNdÊıÑ¿(¢
  9586. _SetOrigin
  9587. °dONLNdı¿)<
  9588. , you should °dONLNd˝ı⁄)B,set the clip region so that you can continue°dONLNd*Ñ
  9589. Î()¢drawing into the port.°dONLNdA<%6(AZ1The number of bits per pixel implies the maximum °dONLNdr6%˛)˙(number of available colors in a graphics°dONLNdõ%<1…(MZenvironment, at least roughly °dONLNdπ%…1˛)ç?speaking. The relationship between the number of bits per pixel°dONLNd˘1<=a(YZand the °dONLNd1a=·)%Nnumber of available colors is discussed in the “Graphics Overview” chapter of °dONLNdO1·=˛(YˇInside°dONLNdV=<Ip(eZ
  9590. Macintosh °dONLNd`=pIx)4V°dONLNda=wI#)"olume VI, pages 16-8 through 16-9.°dONLNdÑU<aU(}ZIf an °dONLNdäUUa˛)Vindexed-color graphics environment is being made, then a color table must be passed to°dONLNd·a<mõ(âZKCreateOffScreen. In ExerciseOffScreen, the color table is retrieved from a °dONLNd,aõm˛(âπ'clut' resource that’s°dONLNdCm<yò(ïZin the application’s °dONLNdXmòy)\resource fork with a call to 
  9591. °dONLNdumy[)á
  9592. _GetCTable
  9593. °dONLNdm[y˛)< . Because CreateOffScreen clones°dONLNd†y<ÖW(°Z@this color table, this 'clut' resource can be purgeable so that °dONLNd‡yWÖ˛(°u"it can be thrown out if its memory°dONLNdÖ<ë…(≠Zis needed for other purposes. 
  9594. °dONLNd!Ö…ë)ç
  9595. _GetCTable
  9596. °dONLNd+Öë°)<! can also be passed some special °dONLNdLÖ°ë˛)úconstants that tell it°dONLNdcë<ù›(πZ!to allocate various system color °dONLNdÑë›ù˛)°8tables that can also be passed to CreateOffScreen. These°dONLNdΩù<©·(≈ZRspecial constants are described on page 17-18 of the “Color QuickDraw” chapter of °dONLNd    ù·©˛(≈ˇInside°dONLNd    ©<µq(—Z
  9597. Macintosh °dONLNd     ©qµy)5V°dONLNd    !©xµ≠)
  9598. olume VI. 
  9599. °dONLNd    +©≠µÈ)5
  9600. _GetCTable
  9601. °dONLNd    5©ÈµV)< allocates memory for °dONLNd    K©Vµ˛)m"these system color tables, so they°dONLNd    nµ<¡.(›Z2should be disposed of after you’re done with them.°dONLNd    °Õ<Ÿ*EA color table could also be built from scratch by allocating it with °dONLNd    ÊÕŸ¨(ıù
  9602. a call to 
  9603. °dONLNd    Õ¨ŸË)-
  9604. _NewHandle
  9605. °dONLNd    ˙ÕËŸ˛)< and°dONLNd    ˇŸ<Âü(Zthen initializing it by °dONLNd
  9606. Ÿü‘)c
  9607. hand. The 
  9608. °dONLNd
  9609. !Ÿ‘Â)5
  9610. ColorTable
  9611. °dONLNd
  9612. +ŸÂ˛)</ structure is documented on pages 48 through 49°dONLNd
  9613. [Â<ÒI(
  9614. Zof °dONLNd
  9615. ^ÂIÒù)
  9616. Inside Macintosh °dONLNd
  9617. oÂùÒ•)TV°dONLNd
  9618. p§Òƒ)olume °dONLNd
  9619. vƒÒÃ) V°dONLNd
  9620. wÂÀÒØ)2. Here’s what each of the fields should be set to:
  9621. °dONLNd
  9622. ™˝<    `(%ZctSeed
  9623. °dONLNd
  9624. ±˝®    
  9625. )lidentification value. °dONLNd
  9626. «˝
  9627.     ˛)b1This is an arbitrary value that should be changed°dONLNd
  9628. ˘    ®º(1Δany °dONLNd
  9629. ˝    º˛)Etime the contents of the color table change so that the inverse table°dONLNd C®!Ï(=Δ can be kept °dONLNd OÏ!˛)D0current. When Color QuickDraw draws anything, it°dONLNd Ä!®-Ì(IΔ
  9630. compares the 
  9631. °dONLNd ç!Ì-)EctSeed
  9632. °dONLNd ì!-í)$ of the color table of the 
  9633. °dONLNd Æ!í-∂)ÅPixMap
  9634. °dONLNd ¥!∂-›)$ of the °dONLNd º!›-˛)'current
  9635. °dONLNd ƒ-®9“(UΔGDevice
  9636. °dONLNd À-“9
  9637. )*
  9638.  against the 
  9639. °dONLNd ÿ-
  9640. 9=);iTabSeed
  9641. °dONLNd ‡-=9†)0 field of the inverse °dONLNd ˆ-†9˛)ctable of the current
  9642. °dONLNd 9®E“(aΔGDevice
  9643. °dONLNd 9“E‹)*. °dONLNd 9‹E˛)
  9644. 5If they’re the same, then Color QuickDraw uses colors°dONLNd JE®Q(mΔaccording to that °dONLNd \EQ˛)`/inverse table. If they’re different, then Color°dONLNd åQ®]˘(yΔQuickDraw first °dONLNd úQ˘]˛)Q5rebuilds the inverse table according to the new color°dONLNd “]®i(ÖΔtable’s contents and its 
  9645. °dONLNd Î]iJ)riTabSeed
  9646. °dONLNd Û]JiZ)0 is °dONLNd ˜]Zi˛)!set to the value of the new color°dONLNd
  9647. i®u (ëΔtable’s 
  9648. °dONLNd
  9649. !i uÓ)"ctSeed
  9650. °dONLNd
  9651. 'iÓu†)$); then the rebuilt inverse table is used. ¡X¡
  9652. (÷Z2QD 13 - Principia Off-Screen Graphics Environments(÷˙29)
  9653.  of 51(ÏZM.QD.PrincipiaOffScreenˇ$l◊#ˇ ˇˇˇˇ#◊ 
  9654. IR,Times
  9655. .+6-Macintosh Technical Notes /4/˘
  9656. °dONLNdÑ)£+lWhen ,
  9657. Courier
  9658. °dONLNd£)Ÿ)    _CopyBits
  9659. °dONLNdŸ).)6 is called with the 
  9660. °dONLNd".)X)UsrcCopy
  9661. °dONLNd)X)Ç)*
  9662.  transfer °dONLNd3Ç)∂)*
  9663. mode, the 
  9664. °dONLNd=∂)⁄)4ctSeed
  9665. °dONLNdD)Ñ5·(Q¢fields of the source °dONLNdY)·5⁄)]3and destination pixel maps are compared. If they’re°dONLNdç5ÑA—(]¢the same, then 
  9666. °dONLNdú5—A)M    _CopyBits
  9667. °dONLNd•5A⁄)6* simply transfers the source pixels to the°dONLNd–AÑMÌ(i¢destination with no °dONLNd‰AÌM⁄)i-mapping of colors. If they’re different, then
  9668. °dONLNdMÑY∫(u¢    _CopyBits
  9669. °dONLNdM∫YS)6  checks each entry of the color °dONLNd;MSY⁄)ôtables to determine whether°dONLNdWYÑe(Å¢they have the same colors °dONLNdqYe⁄)Å+for the same pixel values. If they do, then
  9670. °dONLNdùeÑq∫(碠   _CopyBits
  9671. °dONLNd¶e∫q€)6 again °dONLNd≠e€q⁄)!5simply transfers the source pixels to the destination°dONLNd„qÑ}‰(ô¢with no mapping of °dONLNdˆq‰}f)`colors. If they don’t, then 
  9672. °dONLNdqf}ú)Ç    _CopyBits
  9673. °dONLNdqú}⁄)6  maps colors°dONLNd(}ÑâΔ(•¢in the source 
  9674. °dONLNd6}ΔâÍ)BPixMap
  9675. °dONLNd<}Íâr)$ to the colors in the current °dONLNdZ}râ⁄)àgraphics environment°dONLNdoâÑï(±¢according to the inverse table °dONLNdéâïU)åof the current 
  9676. °dONLNdùâUï)EGDevice
  9677. °dONLNd§âïù)*. The 
  9678. °dONLNd™âùï¡)ctSeed
  9679. °dONLNd∞â¡ï⁄)$ field°dONLNd∑ïѰg(Ω¢0of a color table should be changed whenever its °dONLNdÁïg°⁄)„contents are changed so°dONLNdˇ°Ñ≠ò(…¢that 
  9680. °dONLNd°ò≠Œ)    _CopyBits
  9681. °dONLNd
  9682. °Œ≠F)6 doesn’t make the wrong °dONLNd%°F≠⁄)xassumptions about the equality°dONLNdD≠ÑπH(’¢+of the source and destination color tables.°dONLNdq≈Ñ—å*Y°dONLNdr≈ã— )
  9683. ou can get a °dONLNd≈ —⁄)?7seed value for a new color table by assigning to it the°dONLNd∑—Ñ›¬(˘¢result of the 
  9684. °dONLNd≈—¬›˛)>
  9685. _GetCTSeed
  9686. °dONLNdœ—˛›á)< routine, documented in the °dONLNdΗá›⁄)â“Color Manager”°dONLNd˚›ÑÈ©(¢chapter °dONLNd›©È∑)%of °dONLNd›∑È
  9687. )Inside Macintosh °dONLNd›
  9688. È)VV°dONLNd›È5)olume °dONLNd›5È=)!V°dONLNd›<È⁄)!, page 143. If the contents of an°dONLNdAÈÑıª(¢;existing color table are changed, then it should be passed °dONLNd|Ȫı⁄(Ÿto the
  9689. °dONLNdÉıÑÃ(¢ _CTabChanged
  9690. °dONLNdèıÃé)H* routine which assigns a new value to its 
  9691. °dONLNdπıé≤)¬ctSeed
  9692. °dONLNdøı≤µ)$ °dONLNd¿ıµ⁄)    field. If°dONLNd Ñ
  9693. ò()¢the 
  9694. °dONLNdŒò
  9695. ‡) _CTabChanged
  9696. °dONLNd⁄‡
  9697. p)H routine isn’t available (it’s °dONLNd˘p
  9698. ⁄)êavailable with 32-Bit°dONLNd
  9699. Ñπ(5¢9QuickDraw and is included with the system beginning with °dONLNdH
  9700. π⁄(5◊system°dONLNdOÑ%#(A¢ software version 7.0), then the 
  9701. °dONLNdo#%G)üctSeed
  9702. °dONLNduG%õ)$ field should be °dONLNdÜõ%⁄)T given a new°dONLNdí%Ñ1˝(M¢value with another call to 
  9703. °dONLNd≠%˝19)y
  9704. _GetCTSeed
  9705. °dONLNd∑%91=)<.
  9706. °dONLNdπ=IB(e6ctFlags
  9707. °dONLNd¡=ÑIù)l8indicates the Boolean characteristics of a color table. °dONLNd˘=ùI⁄(eª If the most°dONLNdIÑU‡(q¢significant bit of 
  9708. °dONLNdI‡U
  9709. )\ctFlags
  9710. °dONLNdI
  9711. Uq)* is clear, then the 
  9712. °dONLNd3IqUè)gvalue
  9713. °dONLNd8IèUñ) °dONLNd9IñU⁄)
  9714. field of each
  9715. °dONLNdGUÑa∫(}¢    ColorSpec
  9716. °dONLNdPU∫a˘)6 entry in the 
  9717. °dONLNd^U˘a#)?ctTable
  9718. °dONLNdeU#a•)* array is interpreted as the °dONLNdÇU•a⁄)Ç pixel value°dONLNdéaÑmñ(â¢for °dONLNdíañm5)"the color that’s specified in the 
  9719. °dONLNd¥a5mG)ürgb
  9720. °dONLNd∑aGm§) field in the same 
  9721. °dONLNd a§m⁄)]    ColorSpec
  9722. °dONLNd‘mÑyñ(ï¢entr°dONLNdÿmñyú)y°dONLNdŸmõy¢). °dONLNd€m¢y™)Y°dONLNd‹m©yÀ)ou can °dONLNd„mÀy⁄)"9build a color table with nonconsecutive pixel values this°dONLNdyÑÖí(°¢wa°dONLNdyíÖò)y°dONLNd yóÖ´). If °dONLNd%y´Ö1)this bit is set, then all the 
  9723. °dONLNdCy1ÖO)Üvalue
  9724. °dONLNdHyOÖ⁄) fields in the color table are°dONLNdgÖÑë(≠¢ignored and the index of each 
  9725. °dONLNdÖÖëH)é    ColorSpec
  9726. °dONLNdéÖHëâ)6 record in the 
  9727. °dONLNdùÖâë≥)ActTable
  9728. °dONLNd§Ö≥ë∂)* °dONLNd•Ö∂ë⁄)array is°dONLNdÆëÑùá(π¢7that record’s pixel value. It’s your choice whether to °dONLNdÂëáù⁄(π•clear this bit and°dONLNd¯ùÑ©≠(≈¢set the 
  9729. °dONLNdù≠©À))value
  9730. °dONLNdùÀ©[) fields or set this bit and °dONLNd!ù[©ó)ê ignore the 
  9731. °dONLNd,ùó©µ)<value
  9732. °dONLNd1ùµ©⁄) fields;°dONLNd:©ÑµÑ(—¢<traditionally this bit is clear for off-screen color tables.°dONLNdx¡ÑÕ!*$If the next most significant bit of 
  9733. °dONLNdú¡!ÕK)ùctFlags
  9734. °dONLNd£¡KÕï)* is set, then the 
  9735. °dONLNdµ¡ïÕ≥)Jvalue
  9736. °dONLNd∫¡≥Õ⁄)     field of°dONLNdƒÕÑŸú(ı¢each 
  9737. °dONLNd…ÕúŸ“)    ColorSpec
  9738. °dONLNd“Õ“Ÿ’)6 °dONLNd”Õ’Ÿ)record in the 
  9739. °dONLNd·ÕŸ@)ActTable
  9740. °dONLNdËÕ@Ÿñ)* array is used by 
  9741. °dONLNd˙ÕñŸÃ)V    _CopyBits
  9742. °dONLNd    Õß⁄)6 as°dONLNd    ŸÑÂ(¢an index into the color °dONLNd    ŸÂŒ)l0palette that’s attached to the destination windo°dONLNd    OŸŒÂ◊)fiw°dONLNd    PŸ÷Â⁄),°dONLNd    RÂÑÒ±(
  9743. ¢and the 
  9744. °dONLNd    Z±Ò√)-rgb
  9745. °dONLNd    ]Â√Òè)& field is ignored. This is documented °dONLNd    ÉÂèÒ⁄)Ãin the “Palette°dONLNd    ìÒÑ˝Á(¢Manager” chapter of °dONLNd    ßÒÁ˝;)cInside Macintosh °dONLNd    ∏Ò;˝C)TV°dONLNd    πÒB˝Æ)olume VI, page 20-17.°dONLNd    –    Ñ∂(1¢
  9746. The other °dONLNd    ⁄    ∂⁄)2=bits are reserved for future use. If you create a color table°dONLNd
  9747. Ñ!(=¢from scratch, these other °dONLNd
  9748. 2!⁄)|,bits must be set to zero. If you use a color°dONLNd
  9749. _!Ñ-“(I¢Htable that’s generated by the system, then these bits must be preserved.
  9750. °dONLNd
  9751. ®9E<(a6ctSize
  9752. °dONLNd
  9753. Ø9ÑEº)l the number °dONLNd
  9754. ∫9ºEy)8'of color table entries minus 1. Normall°dONLNd
  9755. ·9yE)Ωy°dONLNd
  9756. ‚9~E⁄), this field is set to°dONLNd
  9757. ˘EÑQ¥(m¢
  9758. 1, 3, 15, °dONLNd E¥Q¬)08or 255 for 1-, 2-, 4-, and 8-bits per pixel, respectivel°dONLNd ;E¬Q»(m‡y°dONLNd <E«Q⁄). In°dONLNd AQÑ](y¢special cases, it’s reasonable °dONLNd `Q]⁄)ä'to have less than the maximum number of°dONLNd à]ÑiU(Ö¢,entries for the pixel depth. For example, a °dONLNd ¥]Ui⁄)—color table for an 8-bit per°dONLNd —iÑuW(ë¢+pixel graphics environment could have just °dONLNd ¸iWu⁄)”150 entries, in which case°dONLNd uÑÅñ(ù¢the 
  9759. °dONLNd uñÅ∫)ctSize
  9760. °dONLNd !u∫ÅX)$! field should hold 149. For this °dONLNd BuXÅ⁄)ûcase, it’s still important to°dONLNd `ÅÑç(©¢allocate as much space in °dONLNd zÅç⁄)~)the color table for the maximum number of ¡4¡˘
  9761. (÷630)
  9762.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ◊#ˇ ˇˇˇˇ#◊ 
  9763. IR,Times
  9764. .+Z-Developer Support Center(-Ï
  9765. March 1992 /X/
  9766. °dONLNd®)N(EΔ$entries for a pixel depth and clear °dONLNd$N)˛)¶$the entries you’re not using to zero°dONLNdI)®5√(QΔ9because some parts of Color QuickDraw assume the size of °dONLNdÇ)√5˛(Q·
  9767. a color table°dONLNdê5®A(]Δbased on the pixel depth.,
  9768. Courier
  9769. °dONLNd™M<Yf(uZctTable
  9770. °dONLNd≤M®Y )larray of colors and °dONLNdΔM Y˛)d2pixel values. This table defines all the available°dONLNd˘Y®eÂ(ÅΔcolors in the °dONLNdYÂe†)=(color table and their pixel values. The 
  9771. °dONLNd/Y†eæ)ªvalue
  9772. °dONLNd4Yæe˛) field of each
  9773. °dONLNdCe®qfi(çΔ    ColorSpec
  9774. °dONLNdLefiqû)6% record indicates that color’s pixel °dONLNdqeûq˛)¿value if the most°dONLNdÉq®}¯(ôΔsignificant bit of 
  9775. °dONLNdñq¯}")PctFlags
  9776. °dONLNdùq"}¢)* is clear. It’s ignored if the °dONLNdºq¢}˛)Ämost significant bit°dONLNd—}®âµ(•Δof 
  9777. °dONLNd‘}µâfl)
  9778. ctFlags
  9779. °dONLNd€}flâ)*
  9780.  is set. The 
  9781. °dONLNdË}â8);value
  9782. °dONLNdÌ}8â˛), field is used as an index into a palette if°dONLNdâ®ï@(±Δ!the next most significant bit of 
  9783. °dONLNd;â@ïj)òctFlags
  9784. °dONLNdBâjïz)* is °dONLNdFâzïÏ)set, in which case the 
  9785. °dONLNd]âÏï˛)rrgb
  9786. °dONLNdaï®°v(ΩΔ,field is ignored. See the discussion of the 
  9787. °dONLNdçïv°†)ŒctFlags
  9788. °dONLNdîΩ)* field °dONLNdõïΩ°˛)earlier in this°dONLNd´°®≠(…ΔNote for more details.°dONLNd¬π<≈p(·ZWarning:°dONLNdÀπÑ≈L)H(Color QuickDraw’s text-drawing routines °dONLNdÛπL≈⁄)»assume that the color table of°dONLNd≈Ñ—ò(Ì¢the °dONLNd≈ò—⁄):destination graphics environment has the maximum number of°dONLNdQ—Ñ›(˘¢"colors for the pixel depth of the °dONLNds—›⁄)ó'graphics environment, and that white is°dONLNdõ›ÑÈ%(¢#the first entry in the color table °dONLNdæ›%È•)°and black is the last entr°dONLNdÿ›•È´)Äy°dONLNdŸ›™È⁄)
  9789. . If these°dONLNd‰ÈÑı≈(¢Gconditions aren’t satisfied, then the resulting image is unpredictable.°dONLNd,<
  9790. ()Z)The code fragment in Listing 6 shows how °dONLNdU
  9791. ˛)÷1to allocate a 256-entry color table from scratch.°dONLNdá
  9792. <    (5Z*Color tables have a variable size, so the 
  9793. °dONLNd±
  9794.     E)Õ
  9795. _NewHandle
  9796. °dONLNdª
  9797. E˛)<& call has to calculate the size of the
  9798. °dONLNd‚<%x(AZ
  9799. ColorTable
  9800. °dONLNdÏx%Δ)<? record plus the maximum number of color table entries for the °dONLNd+Δ%˛(A‰ pixel depth°dONLNd7%<1ƒ(MZmultiplied by the size of a 
  9801. °dONLNdS%ƒ1˙)à    ColorSpec
  9802. °dONLNd\%˙1ˇ)6 °dONLNd]%ˇ1')record. 
  9803. °dONLNde%'1c)(
  9804. kNumColors
  9805. °dONLNdo%c1˛)< - 1 is used in the calculation°dONLNdè1<=d(YZbecause °dONLNdó1d=¨)(the size of the 
  9806. °dONLNdß1¨=Ë)H
  9807. ColorTable
  9808. °dONLNd±1Ë=Ñ)<! record includes the size of one 
  9809. °dONLNd“1Ñ=∫)ú    ColorSpec
  9810. °dONLNd€1∫=˛)6 entry in most°dONLNdÍ=<Iø(eZdevelopment environments.°dONLNdU<a∫*MPW Pascal Listing 6
  9811.     °dONLNdm<xU*CONST°dONLNdw<Ç@*
  9812. 4   kNumColors = 256; {Number of color table entries}°dONLNdTã<ñK*VAR°dONLNdXï<†Y*
  9813. 9   newColors: CTabHandle; {Handle to the new color table}°dONLNdíü<™^*
  9814. :   index:     Integer;    {Index into the table of colors}°dONLNdÕ≥<æ    *)(* Allocate memory for the color table *)°dONLNd˜Ω<»h*
  9815. <newColors := CTabHandle(NewHandleClear(SizeOf (ColorTable) +°dONLNd4«<“*
  9816. -      SizeOf(ColorSpec) * (kNumColors - 1)));°dONLNdb—<‹¥*
  9817. IF newColors <> NIL THEN°dONLNd{€<Êd*
  9818.    BEGIN°dONLNdÑÂ<·*
  9819. !      (* Initialize the fields *)°dONLNd¶Ô<˙˙*
  9820. &      newColors^^.ctSeed := GetCTSeed;°dONLNdÕ˘<◊*
  9821.       newColors^^.ctFlags := 0;°dONLNdÌ<*
  9822. +      newColors^^.ctSize := kNumColors - 1;°dONLNd<"**      (* Initialize the table of colors *)°dONLNdD!<,    *
  9823. )      FOR index := 0 TO kNumColors - 1 DO°dONLNdn+<6Ç*
  9824.          BEGIN°dONLNd}5<@J*
  9825. 6            newColors^^.ctTable[index].value := index;°dONLNd¥?<Jw*
  9826. ?            newColors^^.ctTable[index].rgb.red := someRedValue;°dONLNdÙI<Tã*
  9827. C            newColors^^.ctTable[index].rgb.green := someGreenValue;°dONLNd    8S<^|*
  9828. @            newColors^^.ctTable[index].rgb.blue := someBlueValue°dONLNd    y]<hx*
  9829.          END°dONLNd    Üg<rZ*
  9830.    END ¡X¡
  9831. *H2QD 13 - Principia Off-Screen Graphics Environments(÷˙31)
  9832.  of 51(ÏZM.QD.PrincipiaOffScreenˇ◊#ˇ ˇˇˇˇ#◊ 
  9833. IR,Times
  9834. .+6-Macintosh Technical Notes /4/˘
  9835. °dONLNd){*MPW C Listing 6,
  9836. Courier
  9837.     °dONLNd5@:*:#define kNumColors 256 /* Number of color table entries */°dONLNdKIT5*9CTabHandle newColors; /* Handle to the new color table */°dONLNdÖS^:*
  9838. :short      index;     /* Index into the table of colors */°dONLNd¿grÂ*)/* Allocate memory for the color table */°dONLNdÍq|I*
  9839. =newColors = (CTabHandle)NewHandleClear( sizeof (ColorTable) +°dONLNd({Ü*
  9840. 0        sizeof (ColorSpec) * (kNumColors - 1) );°dONLNdYÖêÅ*
  9841. if (newColors != nil)°dONLNdoèö*
  9842. {°dONLNdqô§≥*
  9843.     /* Initialize the fields */°dONLNdë£Æ€*
  9844. '    (**newColors).ctSeed = GetCTSeed();°dONLNdπ≠∏Æ*
  9845.     (**newColors).ctFlags = 0;°dONLNdÿ∑¬Í*
  9846. *    (**newColors).ctSize = kNumColors - 1;°dONLNdÀ÷‡*(    /* Initialize the table of colors */°dONLNd,’‡*
  9847. 0    for (index = 0; index < kNumColors; index++)°dONLNd]flÍ1*
  9848.     {°dONLNdcÈÙ*
  9849. 3        (**newColors).ctTable[index].value = index;°dONLNdóÛ˛D*
  9850. <        (**newColors).ctTable[index].rgb.red = someRedValue;°dONLNd‘˝X*
  9851. @        (**newColors).ctTable[index].rgb.green = someGreenValue;°dONLNdN*
  9852. >        (**newColors).ctTable[index].rgb.blue = someBlueValue;°dONLNdT1*
  9853.     }°dONLNdZ&*
  9854. }
  9855. °dONLNd\1=R*    Changing °dONLNde1R=[):Y°dONLNdf1Z=π)our Environment°dONLNdvIUΔ(q6WAfter you create an off-screen graphics environment with certain dimensions, you might °dONLNdÕIΔU⁄(q‰later°dONLNd”Ua≈(}6#want to change its size, depth, or °dONLNdˆU≈a⁄)≠6color table without creating a completely new graphics°dONLNd-amW(â67environment from scratch and without needing to redraw °dONLNddaWm⁄(âuthe existing image. The°dONLNd|my≠(ï6MUpdateOffScreen routine in Listing 7 shows just one way to do this. It takes °dONLNd…m≠y⁄(ïÀthe same°dONLNd“yÖê(°6Lparameters that CreateOffScreen (defined in Listing 1) does, but instead of °dONLNdyêÖ⁄(°Æcreating a new
  9856. °dONLNd-ÖëN(≠6    CGrafPort
  9857. °dONLNd6ÖNëm)6 and 
  9858. °dONLNd;Ömëó)GDevice
  9859. °dONLNdBÖóëØ)*, it °dONLNdGÖØëó)*alters the ones that you pass through the 
  9860. °dONLNdqÖóë¡)ËupdPort
  9861. °dONLNdxÖ¡ë⁄)* and
  9862. °dONLNd}ëùT(π6
  9863. updGDevice
  9864. °dONLNdáëTùü)< parameters. If °dONLNdóëüù≤)Kthe 
  9865. °dONLNdõë≤ùË)    newBounds
  9866. °dONLNd§ëËù⁄)61 parameter specifies an empty rectangle, then the°dONLNd÷ù©t(≈6existing boundary °dONLNdËùt©ƒ)\Crectangle for the off-screen graphics environment is used. Similarl°dONLNd+ùƒ© (≈‚y°dONLNd,ù…©⁄), if
  9867. °dONLNd1©µH(—6newDepth
  9868. °dONLNd9©Hµ4)06 is zero, then the existing depth is used; and if the 
  9869. °dONLNdo©4µj)Ï    newColors
  9870. °dONLNdx©jµû)6  parameter °dONLNdÉ©ûµ⁄)4 is NIL, then°dONLNd굡Q(›6
  9871. the existing °dONLNdùµQ¡T)96color table is used. UpdateOffScreen alters the given 
  9872. °dONLNd”µT¡ä(›r    CGrafPort
  9873. °dONLNd‹µä¡£)6 and 
  9874. °dONLNd·µ£¡Õ)GDevice
  9875. °dONLNd˵ա⁄)* to°dONLNdÏ¡Õ@(È6the new °dONLNdÙ¡@Õ¸)()settings, but it completely replaces the 
  9876. °dONLNd¡¸Õ )ºPixMap
  9877. °dONLNd#¡ Õ⁄)$). After all the alterations are made, the°dONLNdMÕŸ+(ı6old 
  9878. °dONLNdQÕ+ŸO)PixMap
  9879. °dONLNdWÕOŸ )$’s image is copied to the °dONLNdqÕ Ÿ„){new 
  9880. °dONLNduÕ„Ÿ)PixMap
  9881. °dONLNd{ÕŸê)$’s image, and then the old 
  9882. °dONLNdñÕ꟥)âPixMap
  9883. °dONLNdúÕ¥Ÿ⁄)$ and its°dONLNd•ŸÂv(6image are disposed.°dONLNdπÒ˝ñ*MPW Pascal Listing 7
  9884.     °dONLNdŒ    ï*FUNCTION UpdateOffScreen(°dONLNdË]*
  9885. A   newBounds:  Rect;       {New bounding rectangle of off-screen}°dONLNd*({*
  9886. G   newDepth:   Integer;    {New number of bits per pixel in off-screen}°dONLNdr'2l*
  9887. D   newColors:  CTabHandle; {New color table to assign to off-screen}°dONLNd∑1<{*
  9888. G   updPort:    CGrafPtr;   {Returns a pointer to the updated CGrafPort}°dONLNdˇ;Fl*
  9889. D   updGDevice: GDHandle    {Returns a handle to the updated GDevice}°dONLNd    DEPT*
  9890.    ): OSErr;°dONLNd    QYd@*   CONST°dONLNd    Zcn{*
  9891. G      kMaxRowBytes = $3FFE; {Maximum number of bytes per row of pixels} ¡4¡˘
  9892. *L32)
  9893.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇÓ◊#ˇ ˇˇˇˇ#◊ 
  9894. IR,Times
  9895. .+Z-Developer Support Center(-Ï
  9896. March 1992 /X/,
  9897. Courier
  9898.     °dONLNd<(Z(DZ   VAR°dONLNd'<2ö*
  9899. F      newPixMap:   PixMapHandle; {Handle to the new off-screen PixMap}°dONLNdN1<<ö*
  9900. F      oldPixMap:   PixMapHandle; {Handle to the old off-screen PixMap}°dONLNdï;<Fã*
  9901. C      bounds:      Rect;         {Boundary rectangle of off-screen}°dONLNdŸE<PÅ*
  9902. A      depth:       Integer;      {Depth of the off-screen PixMap}°dONLNdO<Z§*
  9903. H      bytesPerRow: Integer;      {Number of bytes per row in the PixMap}°dONLNddY<dã*
  9904. C      colors:      CTabHandle;   {Colors for the off-screen PixMap}°dONLNd®c<nY*
  9905. 9      savedFore:   RGBColor;     {Saved foreground color}°dONLNd‚m<xY*
  9906. 9      savedBack:   RGBColor;     {Saved background color}°dONLNdw<Ǭ*
  9907. N      aColor:      RGBColor;     {Used to set foreground and background color}°dONLNdkÅ<å§*
  9908. H      qdVersion:   LongInt;      {Version of QuickDraw currently in use}°dONLNd¥ã<ñ∏*
  9909. L      savedPort:   GrafPtr;      {Pointer to GrafPort used for save/restore}°dONLNdï<†Æ*
  9910. J      savedDevice: GDHandle;     {Handle to GDevice used for save/restore}°dONLNdLü<™ê*
  9911. D      savedState:  SignedByte;   {Saved state of color table handle}°dONLNdë©<¥E*
  9912. 5      error:       OSErr;        {Returns error code}°dONLNd«Ω<»U*BEGIN°dONLNdÕ«<“,*
  9913. 0   (* Initialize a few things before we begin *)°dONLNd˛—<‹†*
  9914.    newPixMap := NIL;°dONLNd€<Êñ*
  9915.    error := noErr;°dONLNd&Ô<˙^*:   (* Keep the old bounds rectangle, or get the new one *)°dONLNda˘<◊*
  9916.    IF EmptyRect(newBounds) THEN°dONLNdÅ<·*
  9917. !      bounds := updPort^.portRect°dONLNd£
  9918. <_*
  9919.    ELSE°dONLNd´<"æ*
  9920.       bounds := newBounds;°dONLNdΔ+<6'*/   (* Keep the old depth, or get the old one *)°dONLNdˆ5<@Ø*
  9921.    IF newDepth = 0 THEN°dONLNd?<J"*
  9922. .      depth := updPort^.portPixMap^^.pixelSize°dONLNd=I<T_*
  9923.    ELSE°dONLNdES<^¥*
  9924.       depth := newDepth;°dONLNd^g<r∏*L   (* Get the old clut, or save new clut’s state and make it nonpurgeable *)°dONLNd´q<|æ*
  9925.    IF newColors = NIL THEN°dONLNdΔ{<Ü*
  9926. -      colors := updPort^.portPixMap^^.pmTable°dONLNdÙÖ<ê_*
  9927.    ELSE°dONLNd¸è<ös*
  9928.       BEGIN°dONLNdô<§@*
  9929. 4         savedState := HGetState(Handle(newColors));°dONLNd=£<Æı*
  9930. %         HNoPurge(Handle(newColors));°dONLNdc≠<∏Õ*
  9931.          colors := newColors;°dONLNdÅ∑<¬n*
  9932.  
  9933.       END;°dONLNdåÀ<÷ü*G   (* Calculate the number of bytes per row in the off-screen PixMap *)°dONLNd‘’<‡≥*
  9934. K   bytesPerRow := ((depth * (bounds.right - bounds.left) + 31) DIV 32) * 4;°dONLNd È<Ù**   (* Get the current QuickDraw version *)°dONLNdKÛ<˛Y*
  9935. 9   error := Gestalt (gestaltQuickdrawVersion, qdVersion);°dONLNdÖ˝<ñ*
  9936.    error := noErr;°dONLNdò<¬*N   (* Make sure depth is indexed or depth is direct and 32-Bit QD installed *)°dONLNdÁ<&Å*
  9937. A   IF (depth = 1) OR (depth = 2) OR (depth = 4) OR (depth = 8) OR°dONLNd)%<0Ã*
  9938. P         (((depth = 16) OR (depth = 32)) AND (qdVersion >= gestalt32BitQD)) THEN°dONLNdz/<:s*
  9939.       BEGIN°dONLNdÜ9<DÃ*
  9940. P         (* Maximum number of bytes per row is 16,382; make sure within range *)°dONLNd◊C<N*
  9941. ,         IF bytesPerRow <= kMaxRowBytes THEN°dONLNd    M<Xë*
  9942.             BEGIN°dONLNd    W<bÃ*
  9943. P               (* Make sure a color table is provided if the depth is indexed *)°dONLNd    ga<l·*
  9944. !               IF depth <= 8 THEN°dONLNd    âk<v˙*
  9945. &                  IF colors = NIL THEN°dONLNd    ∞u<Ä∏*
  9946. L                     (* Indexed depth and clut is NIL; is parameter error *)°dONLNd    ˝<äˇ*
  9947. '                     error := paramErr;°dONLNd
  9948. %â<îá*
  9949.             END ¡X¡
  9950. *&2QD 13 - Principia Off-Screen Graphics Environments(÷˙33)
  9951.  of 51(ÏZM.QD.PrincipiaOffScreenˇå◊#ˇ ˇˇˇˇ#◊ 
  9952. IR,Times
  9953. .+6-Macintosh Technical Notes /4/˘,
  9954. Courier
  9955.     °dONLNd(Y*
  9956.          ELSE°dONLNd'2î*
  9957. L            (* # of bytes per row is more than 16,382; is parameter error *)°dONLNd[1<Æ*
  9958.             error := paramErr;°dONLNdz;FE*
  9959.           END°dONLNdÑEP;*
  9960.    ELSE°dONLNdåOZ+*
  9961. 7      (* Pixel depth isn’t valid; is parameter error *)°dONLNdƒYdê*
  9962.       error := paramErr;°dONLNd›mxô*M   (* If sanity checks succeed, attempt to update the graphics environment *)°dONLNd+wÇê*
  9963.    IF error = noErr THEN°dONLNdDÅåO*
  9964.       BEGIN°dONLNdPãñÃ*
  9965. $         (* Allocate a new PixMap *)°dONLNduï†g*
  9966. C         newPixMap := PixMapHandle(NewHandleClear(SizeOf(PixMap)));°dONLNdπü™Ω*
  9967. !         IF newPixMap <> NIL THEN°dONLNd€©¥w*
  9968.               BEGIN°dONLNdÔ≥æq*
  9969. E               (* Initialize the new PixMap for off-screen drawing *)°dONLNd5Ω»{*
  9970. G               error := SetUpPixMap(depth, bounds, colors, bytesPerRow,°dONLNd}«“∏*
  9971.                       newPixMap);°dONLNdû—‹Ã*
  9972. $               IF error = noErr THEN°dONLNd√€Êã*
  9973.                   BEGIN°dONLNd€Âè*
  9974. K                     (* Save old PixMap and install new, initialized one *)°dONLNd'Ô˙&*
  9975. 6                     oldPixMap := updPort^.portPixMap;°dONLNd^˘&*
  9976. 6                     updPort^.portPixMap := newPixMap;°dONLNdï
  9977. £*O                     (* Save current port & GDevice; set ones we’re updating *)°dONLNdÂ"‡*
  9978. (                     GetPort(savedPort);°dONLNd!,*
  9979. /                     savedDevice := GetGDevice;°dONLNd>+6*
  9980. /                     SetPort(GrafPtr(updPort));°dONLNdn5@Ù*
  9981. ,                     SetGDevice(updGDevice);°dONLNdõITô*M                     (* Set portRect, visRgn, clipRgn to given bounds rect *)°dONLNdÈS^
  9982. *
  9983. 1                     updPort^.portRect := bounds;°dONLNd]h&*
  9984. 6                     RectRgn(updPort^.visRgn, bounds);°dONLNdRgr÷*
  9985. &                     ClipRect(bounds);°dONLNdy{ܢ*-                     (* Update the GDevice *)°dONLNdßÖê+*
  9986. 7                     IF newPixMap^^.pixelSize <= 8 THEN°dONLNdflèö+*
  9987. 7                        updGDevice^^.gdType := clutType°dONLNdô§ï*
  9988.                      ELSE°dONLNd1£Æ:*
  9989. :                        updGDevice^^.gdType := directType;°dONLNdl≠∏&*
  9990. 6                     updGDevice^^.gdPMap := newPixMap;°dONLNd£∑¬S*
  9991. ?                     updGDevice^^.gdRect := newPixMap^^.bounds;°dONLNd„À÷ô*M                     (* Set color-device bit if PixMap isn’t black & white *)°dONLNd1’‡&*
  9992. 6                     IF newPixMap^^.pixelSize > 1 THEN°dONLNdhflÍÄ*
  9993. H                        SetDeviceAttribute(updGDevice, gdDevType, TRUE);°dONLNd±ÈÙï*
  9994.                      else°dONLNdÀÛ˛Ö*
  9995. I                        SetDeviceAttribute(updGDevice, gdDevType, FALSE);°dONLNd{*G                     (* Save current fore/back colors and set to B&W *)°dONLNd]˘*
  9996. -                     GetForeColor(savedFore);°dONLNdã&˘*
  9997. -                     GetBackColor(savedBack);°dONLNdπ%0ä*
  9998. J                     aColor.red := 0; aColor.green := 0; aColor.blue := 0;°dONLNd    /:Í*
  9999. *                     RGBForeColor(aColor);°dONLNd    /9DÂ*
  10000. )                     aColor.red := $FFFF;°dONLNd    YCNÔ*
  10001. +                     aColor.green := $FFFF;°dONLNd    ÖMXÍ*
  10002. *                     aColor.blue := $FFFF;°dONLNd    ∞WbÍ*
  10003. *                     RGBBackColor(aColor);°dONLNd    €kvÖ*I                     (* Copy old image to the new graphics environment *)°dONLNd
  10004. %uIJ*
  10005. .                     HLock(Handle(oldPixMap));°dONLNd
  10006. Tä≠*
  10007. Q                     CopyBits(BitMapPtr(oldPixMap^)^, GrafPtr(updPort)^.portBits,°dONLNd
  10008. ¶âî]*
  10009. A                           oldPixMap^^.bounds, updPort^.portRect, ¡4¡˘
  10010. *&34)
  10011.  of 51)‚2QD 13 - Principia Off-Screen Graphics Environments+nM.QD.PrincipiaOffScreenˇ†◊#ˇ ˇˇˇˇ#◊ 
  10012. IR,Times
  10013. .+Z-Developer Support Center(-Ï
  10014. March 1992 /X/,
  10015. Courier
  10016.     °dONLNd<(    (DZ)                           srcCopy, NIL);°dONLNd*'<2,*
  10017. 0                     HUnlock(Handle(oldPixMap));°dONLNd[;<FÜ*B                     (* Restore the foreground/background color *)°dONLNdûE<P*
  10018. -                     RGBForeColor(savedFore);°dONLNdÃO<Z*
  10019. -                     RGBBackColor(savedBack);°dONLNd˙c<n1*1                     (* Restore the saved port *)°dONLNd,m<x*
  10020. (                     SetPort(savedPort);°dONLNdUw<Ç*
  10021. -                     SetGDevice(savedDevice);°dONLNdÉã<ñü*G                     (* Get rid of the old PixMap and its dependents *)°dONLNdÀï<†E*
  10022. 5                     DisposPtr(oldPixMap^^.baseAddr);°dONLNdü<™T*
  10023. 8                     DisposeCTable(oldPixMap^^.pmTable);°dONLNd:©<¥E*
  10024. 5                     DisposHandle(Handle(oldPixMap));°dONLNdp≥<æ™*
  10025.                   END;°dONLNdáΩ<»á*
  10026.             END°dONLNdó«<“}*
  10027.  
  10028.          ELSE°dONLNd•—<‹‹*
  10029.                error := MemError;°dONLNdΔ€<Êi*
  10030.          END;°dONLNd–Ô<˙;*3   (* Restore the given state of the color table *)°dONLNd˘<¥*
  10031.    IF colors <> NIL THEN°dONLNd<*
  10032. ,      HSetState(Handle(colors), savedState);°dONLNdJ<"E*5   (* One Last Look Around The House Before We Go… *)°dONLNdÄ!<,π*
  10033.    IF error <> noErr THEN°dONLNdö+<6s*
  10034.       BEGIN°dONLNd¶5<@·*
  10035. !         IF newPixMap <> NIL THEN°dONLNd»?<Jë*
  10036.             BEGIN°dONLNd⁄I<T1*
  10037. 1               IF newPixMap^^.pmTable <> NIL THEN°dONLNd S<^@*
  10038. 4                  DisposCTable(newPixMap^^.pmTable);°dONLNdA]<h6*
  10039. 2               IF newPixMap^^.baseAddr <> NIL THEN°dONLNdtg<r6*
  10040. 2                  DisposPtr(newPixMap^^.baseAddr);°dONLNdßq<|'*
  10041. /               DisposHandle(Handle(newPixMap));°dONLNd◊{<Üå*
  10042.             END;°dONLNdËÖ<ên*
  10043.  
  10044.       END;°dONLNdÛè<ö»*
  10045.    UpdateOffScreen := error;°dONLNdô<§P*
  10046. END;
  10047. °dONLNdØ<ªü*MPW C Listing 7
  10048.     °dONLNd%«<“∏*L#define kMaxRowBytes 0x3FFE /* Maximum number of bytes in a row of pixels */°dONLNdr€<Ê™*OSErr UpdateOffScreen(°dONLNdâÂ<ï*
  10049. E    Rect       *newBounds, /* New bounding rectangle of off-screen */°dONLNdœÔ<˙≥*
  10050. K    short      newDepth,   /* New number of bits per pixel in off-screen */°dONLNd˘<§*
  10051. H    CTabHandle newColors,  /* New color table to assign to off-screen */°dONLNdd<≥*
  10052. K    CGrafPtr   updPort,    /* Returns a pointer to the updated CGrafPort */°dONLNd∞
  10053. <§*
  10054. H    GDHandle   updGDevice) /* Returns a handle to the updated GDevice */°dONLNd˘<"A*
  10055. {°dONLNd˚!<,ü*
  10056. G    PixMapHandle newPixMap;   /* Handle to the new off-screen PixMap */°dONLNdC+<6ü*
  10057. G    PixMapHandle oldPixMap;   /* Handle to the old off-screen PixMap */°dONLNdã5<@ê*
  10058. D    Rect         bounds;      /* Boundary rectangle of off-screen */°dONLNd–?<JÜ*
  10059. B    short        depth;       /* Depth of the off-screen PixMap */°dONLNdI<T©*
  10060. I    short        bytesPerRow; /* Number of bytes per row in the PixMap */°dONLNd]S<^ê*
  10061. D    CTabHandle   colors;      /* Colors for the off-screen PixMap */°dONLNd¢]<h^*
  10062. :    RGBColor     savedFore;   /* Saved foreground color */°dONLNd›g<r^*
  10063. :    RGBColor     savedBack;   /* Saved background color */°dONLNd    q<|«*
  10064. O    RGBColor     aColor;      /* Used to set foreground and background color */°dONLNd    h{<Ü©*
  10065. I    long         qdVersion;   /* Version of QuickDraw currently in use */°dONLNd    ≤Ö<êΩ*
  10066. M    GrafPtr      savedPort;   /* Pointer to GrafPort used for save/restore */ ¡X¡
  10067. **2QD 13 - Principia Off-Screen Graphics Environments(÷˙35)
  10068.  of 51(ÏZM.QD.PrincipiaOffScreenˇP◊#ˇ ˇˇˇˇ#◊ 
  10069. IR,Times
  10070. .+6-Macintosh Technical Notes /4/˘,
  10071. Courier
  10072.     °dONLNd(è*K    GDHandle     savedDevice; /* Handle to GDevice used for save/restore */°dONLNdL'2q*
  10073. E    SignedByte   savedState;  /* Saved state of color table handle */°dONLNdí1<&*
  10074. 6    OSErr        error;       /* Returns error code */°dONLNd…EP
  10075. *1    /* Initialize a few things before we begin */°dONLNd˚OZ|*
  10076.     newPixMap = nil;°dONLNdYdr*
  10077.     error = noErr;°dONLNd#mx?*;    /* Keep the old bounds rectangle, or get the new one */°dONLNd_wÇ≥*
  10078.     if (EmptyRect( newBounds ))°dONLNdÅå«*
  10079. #        bounds = updPort->portRect;°dONLNd£ãñ@*
  10080.     else°dONLNd¨ï†§*
  10081.         bounds = *newBounds;°dONLNd…©¥*0    /* Keep the old depth, or get the old one */°dONLNd˙≥æÜ*
  10082.     if (newDepth == 0)°dONLNdΩ»*
  10083. 2        depth = (**updPort->portPixMap).pixelSize;°dONLNdD«“@*
  10084.     else°dONLNdM—‹ï*
  10085.         depth = newDepth;°dONLNdgÂô*M    /* Get the old clut, or save new clut’s state and make it nonpurgeable */°dONLNdµÔ˙ï*
  10086.     if (newColors == nil)°dONLNdœ˘
  10087. *
  10088. 1        colors = (**updPort->portPixMap).pmTable;°dONLNd@*
  10089.     else°dONLNd
  10090. 
  10091. 1*
  10092.     {°dONLNd"*
  10093. 4        savedState = HGetState( (Handle)newColors );°dONLNdE!,÷*
  10094. &        HNoPurge( (Handle)newColors );°dONLNdl+6ü*
  10095.         colors = newColors;°dONLNdà5@1*
  10096.     }°dONLNdéITÄ*H    /* Calculate the number of bytes per row in the off-screen PixMap */°dONLNd◊S^ä*
  10097. J    bytesPerRow = ((depth * (bounds.right - bounds.left) + 31) >> 5) << 2;°dONLNd"grÔ*+    /* Get the current QuickDraw version */°dONLNdNq|5*
  10098. 9    (void)Gestalt( gestaltQuickdrawVersion, &qdVersion );°dONLNdàÖê£*O    /* Make sure depth is indexed or depth is direct and 32-Bit QD installed */°dONLNdÿèöS*
  10099. ?    if (depth == 1 || depth == 2 || depth == 4 || depth == 8 ||°dONLNdô§ä*
  10100. J            ((depth == 16 || depth == 32) && qdVersion >= gestalt32BitQD))°dONLNdc£Æ1*
  10101.     {°dONLNdi≠∏£*
  10102. O        /* Maximum number of bytes per row is 16,382; make sure within range */°dONLNdπ∑¬‡*
  10103. (        if (bytesPerRow <= kMaxRowBytes)°dONLNd‚¡ÃE*
  10104.             {°dONLNdÏÀ÷ô*
  10105. M            /* Make sure a color table is provided if the depth is indexed */°dONLNd:’‡ü*
  10106.             if (depth <= 8)°dONLNdVflͬ*
  10107. "                if (colors == nil)°dONLNdyÈÙè*
  10108. K                    /*